[llvm] 9c645a9 - [ELF] Move getSectionAndRelocations to ELF.cpp from ELFDumper.cpp

Aiden Grossman via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 9 09:10:36 PST 2023


Author: Aiden Grossman
Date: 2023-03-09T17:10:30Z
New Revision: 9c645a99e4e7451c0073dddea74d52dac7f7e837

URL: https://github.com/llvm/llvm-project/commit/9c645a99e4e7451c0073dddea74d52dac7f7e837
DIFF: https://github.com/llvm/llvm-project/commit/9c645a99e4e7451c0073dddea74d52dac7f7e837.diff

LOG: [ELF] Move getSectionAndRelocations to ELF.cpp from ELFDumper.cpp

This refactoring will allow for this utility function to be used in
other places in the codebase outside of the llvm-readobj tool.

Reviewed By: jhenderson, rahmanl

Differential Revision: https://reviews.llvm.org/D144783

Added: 
    

Modified: 
    llvm/include/llvm/Object/ELF.h
    llvm/lib/Object/ELF.cpp
    llvm/test/tools/llvm-readobj/ELF/call-graph-profile.test
    llvm/test/tools/llvm-readobj/ELF/stack-sizes.test
    llvm/tools/llvm-readobj/ELFDumper.cpp
    llvm/unittests/Object/ELFObjectFileTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h
index 1664ff96542f8..74557d3ddae8b 100644
--- a/llvm/include/llvm/Object/ELF.h
+++ b/llvm/include/llvm/Object/ELF.h
@@ -14,6 +14,7 @@
 #define LLVM_OBJECT_ELF_H
 
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/MapVector.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
@@ -393,6 +394,14 @@ class ELFFile {
   Expected<ArrayRef<uint8_t>> getSegmentContents(const Elf_Phdr &Phdr) const;
   Expected<std::vector<BBAddrMap>> decodeBBAddrMap(const Elf_Shdr &Sec) const;
 
+  /// Returns a map from every section matching \p IsMatch to its relocation
+  /// section, or \p nullptr if it has no relocation section. This function
+  /// returns an error if any of the \p IsMatch calls fail or if it fails to
+  /// retrieve the content section of any relocation section.
+  Expected<MapVector<const Elf_Shdr *, const Elf_Shdr *>>
+  getSectionAndRelocations(
+      std::function<Expected<bool>(const Elf_Shdr &)> IsMatch) const;
+
   void createFakeSections();
 };
 

diff  --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp
index 81c9a097170d8..aaa2abfc42fd1 100644
--- a/llvm/lib/Object/ELF.cpp
+++ b/llvm/lib/Object/ELF.cpp
@@ -706,6 +706,50 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec) const {
   return FunctionEntries;
 }
 
+template <class ELFT>
+Expected<
+    MapVector<const typename ELFT::Shdr *, const typename ELFT::Shdr *>>
+ELFFile<ELFT>::getSectionAndRelocations(
+    std::function<Expected<bool>(const Elf_Shdr &)> IsMatch) const {
+  MapVector<const Elf_Shdr *, const Elf_Shdr *> SecToRelocMap;
+  Error Errors = Error::success();
+  for (const Elf_Shdr &Sec : cantFail(this->sections())) {
+    Expected<bool> DoesSectionMatch = IsMatch(Sec);
+    if (!DoesSectionMatch) {
+      Errors = joinErrors(std::move(Errors), DoesSectionMatch.takeError());
+      continue;
+    }
+    if (*DoesSectionMatch) {
+      if (SecToRelocMap.insert(std::make_pair(&Sec, (const Elf_Shdr *)nullptr))
+              .second)
+        continue;
+    }
+
+    if (Sec.sh_type != ELF::SHT_RELA && Sec.sh_type != ELF::SHT_REL)
+      continue;
+
+    Expected<const Elf_Shdr *> RelSecOrErr = this->getSection(Sec.sh_info);
+    if (!RelSecOrErr) {
+      Errors = joinErrors(std::move(Errors),
+                          createError(describe(*this, Sec) +
+                                      ": failed to get a relocated section: " +
+                                      toString(RelSecOrErr.takeError())));
+      continue;
+    }
+    const Elf_Shdr *ContentsSec = *RelSecOrErr;
+    Expected<bool> DoesRelTargetMatch = IsMatch(*ContentsSec);
+    if (!DoesRelTargetMatch) {
+      Errors = joinErrors(std::move(Errors), DoesRelTargetMatch.takeError());
+      continue;
+    }
+    if (*DoesRelTargetMatch)
+      SecToRelocMap[ContentsSec] = &Sec;
+  }
+  if(Errors)
+    return Errors;
+  return SecToRelocMap;
+}
+
 template class llvm::object::ELFFile<ELF32LE>;
 template class llvm::object::ELFFile<ELF32BE>;
 template class llvm::object::ELFFile<ELF64LE>;

diff  --git a/llvm/test/tools/llvm-readobj/ELF/call-graph-profile.test b/llvm/test/tools/llvm-readobj/ELF/call-graph-profile.test
index 99532a62957fc..5ca5a6682f549 100644
--- a/llvm/test/tools/llvm-readobj/ELF/call-graph-profile.test
+++ b/llvm/test/tools/llvm-readobj/ELF/call-graph-profile.test
@@ -350,3 +350,23 @@ Sections:
 Symbols:
   - Name: foo
   - Name: bar
+
+## Check that we report a warning when we fail to get a section associated with
+## a relocation section.
+
+# RUN: yaml2obj %s --docnum=8 -o %t9.o
+# RUN: llvm-readobj %t9.o --cg-profile 2>&1 | FileCheck %s -DFILE=%t9.o --check-prefix=LLVM-RELOC-NO-SECTIONS
+# RUN: llvm-readobj %t9.o --elf-cg-profile 2>&1 | FileCheck %s -DFILE=%t9.o --check-prefix=LLVM-RELOC-NO-SECTIONS
+
+# LLVM-RELOC-NO-SECTIONS: warning: '[[FILE]]': unable to get CG Profile section(s): SHT_RELA section with index 1: failed to get a relocated section: invalid section index: 255
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_DYN
+  Machine: EM_X86_64
+Sections:
+  - Name: .rela.llvm.call-graph-profile
+    Type: SHT_RELA
+    Info: 0xFF

diff  --git a/llvm/test/tools/llvm-readobj/ELF/stack-sizes.test b/llvm/test/tools/llvm-readobj/ELF/stack-sizes.test
index 1023509713678..c2f25f0d1800c 100644
--- a/llvm/test/tools/llvm-readobj/ELF/stack-sizes.test
+++ b/llvm/test/tools/llvm-readobj/ELF/stack-sizes.test
@@ -870,8 +870,8 @@ Sections:
 # RUN: llvm-readobj --stack-sizes %t18 2>&1 | \
 # RUN:   FileCheck %s --implicit-check-not="warning:" -DFILE=%t18 --check-prefix=INVALID-TARGET
 
-# INVALID-TARGET: warning: '[[FILE]]': SHT_RELA section with index 1: failed to get a relocated section: invalid section index: 255
-# INVALID-TARGET: warning: '[[FILE]]': SHT_RELA section with index 2: failed to get a relocated section: invalid section index: 255
+# INVALID-TARGET: warning: '[[FILE]]': unable to get stack size map section(s): SHT_RELA section with index 1: failed to get a relocated section: invalid section index: 255
+# INVALID-TARGET: SHT_RELA section with index 2: failed to get a relocated section: invalid section index: 255
 
 --- !ELF
 FileHeader:

diff  --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 5615d7579a074..a462dbf2a622d 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -328,12 +328,6 @@ template <typename ELFT> class ELFDumper : public ObjDumper {
   void printRelocatableStackSizes(std::function<void()> PrintHeader);
   void printNonRelocatableStackSizes(std::function<void()> PrintHeader);
 
-  /// Retrieves sections with corresponding relocation sections based on
-  /// IsMatch.
-  void getSectionAndRelocations(
-      std::function<bool(const Elf_Shdr &)> IsMatch,
-      llvm::MapVector<const Elf_Shdr *, const Elf_Shdr *> &SecToRelocMap);
-
   const object::ELFObjectFile<ELFT> &ObjF;
   const ELFFile<ELFT> &Obj;
   StringRef FileName;
@@ -6281,38 +6275,11 @@ void ELFDumper<ELFT>::printNonRelocatableStackSizes(
   }
 }
 
-template <class ELFT>
-void ELFDumper<ELFT>::getSectionAndRelocations(
-    std::function<bool(const Elf_Shdr &)> IsMatch,
-    llvm::MapVector<const Elf_Shdr *, const Elf_Shdr *> &SecToRelocMap) {
-  for (const Elf_Shdr &Sec : cantFail(Obj.sections())) {
-    if (IsMatch(Sec))
-      if (SecToRelocMap.insert(std::make_pair(&Sec, (const Elf_Shdr *)nullptr))
-              .second)
-        continue;
-
-    if (Sec.sh_type != ELF::SHT_RELA && Sec.sh_type != ELF::SHT_REL)
-      continue;
-
-    Expected<const Elf_Shdr *> RelSecOrErr = Obj.getSection(Sec.sh_info);
-    if (!RelSecOrErr) {
-      reportUniqueWarning(describe(Sec) +
-                          ": failed to get a relocated section: " +
-                          toString(RelSecOrErr.takeError()));
-      continue;
-    }
-    const Elf_Shdr *ContentsSec = *RelSecOrErr;
-    if (IsMatch(*ContentsSec))
-      SecToRelocMap[ContentsSec] = &Sec;
-  }
-}
-
 template <class ELFT>
 void ELFDumper<ELFT>::printRelocatableStackSizes(
     std::function<void()> PrintHeader) {
   // Build a map between stack size sections and their corresponding relocation
   // sections.
-  llvm::MapVector<const Elf_Shdr *, const Elf_Shdr *> StackSizeRelocMap;
   auto IsMatch = [&](const Elf_Shdr &Sec) -> bool {
     StringRef SectionName;
     if (Expected<StringRef> NameOrErr = Obj.getSectionName(Sec))
@@ -6322,9 +6289,16 @@ void ELFDumper<ELFT>::printRelocatableStackSizes(
 
     return SectionName == ".stack_sizes";
   };
-  getSectionAndRelocations(IsMatch, StackSizeRelocMap);
 
-  for (const auto &StackSizeMapEntry : StackSizeRelocMap) {
+  Expected<MapVector<const Elf_Shdr *, const Elf_Shdr *>>
+      StackSizeRelocMapOrErr = Obj.getSectionAndRelocations(IsMatch);
+  if (!StackSizeRelocMapOrErr) {
+    reportUniqueWarning("unable to get stack size map section(s): " +
+                        toString(StackSizeRelocMapOrErr.takeError()));
+    return;
+  }
+
+  for (const auto &StackSizeMapEntry : *StackSizeRelocMapOrErr) {
     PrintHeader();
     const Elf_Shdr *StackSizesELFSec = StackSizeMapEntry.first;
     const Elf_Shdr *RelocSec = StackSizeMapEntry.second;
@@ -7148,14 +7122,19 @@ static bool getSymbolIndices(const typename ELFT::Shdr *CGRelSection,
 }
 
 template <class ELFT> void LLVMELFDumper<ELFT>::printCGProfile() {
-  llvm::MapVector<const Elf_Shdr *, const Elf_Shdr *> SecToRelocMap;
-
   auto IsMatch = [](const Elf_Shdr &Sec) -> bool {
     return Sec.sh_type == ELF::SHT_LLVM_CALL_GRAPH_PROFILE;
   };
-  this->getSectionAndRelocations(IsMatch, SecToRelocMap);
 
-  for (const auto &CGMapEntry : SecToRelocMap) {
+  Expected<MapVector<const Elf_Shdr *, const Elf_Shdr *>> SecToRelocMapOrErr =
+      this->Obj.getSectionAndRelocations(IsMatch);
+  if (!SecToRelocMapOrErr) {
+    this->reportUniqueWarning("unable to get CG Profile section(s): " +
+                              toString(SecToRelocMapOrErr.takeError()));
+    return;
+  }
+
+  for (const auto &CGMapEntry : *SecToRelocMapOrErr) {
     const Elf_Shdr *CGSection = CGMapEntry.first;
     const Elf_Shdr *CGRelSection = CGMapEntry.second;
 

diff  --git a/llvm/unittests/Object/ELFObjectFileTest.cpp b/llvm/unittests/Object/ELFObjectFileTest.cpp
index 99595eba0962e..74d6d72cc8bae 100644
--- a/llvm/unittests/Object/ELFObjectFileTest.cpp
+++ b/llvm/unittests/Object/ELFObjectFileTest.cpp
@@ -808,3 +808,104 @@ TEST(ELFObjectFileTest, ExecutableWithRelocs) {
   RelocatableFileYamlString += ContentsString;
   DoCheck(RelocatableFileYamlString);
 }
+
+TEST(ELFObjectFileTest, GetSectionAndRelocations) {
+  StringRef HeaderString(R"(
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+)");
+
+  using Elf_Shdr = Elf_Shdr_Impl<ELF64LE>;
+
+  auto DoCheckSucceeds = [&](StringRef ContentsString,
+                             std::function<Expected<bool>(const Elf_Shdr &)>
+                                 Matcher) {
+    SmallString<0> Storage;
+    SmallString<128> FullYamlString(HeaderString);
+    FullYamlString += ContentsString;
+    Expected<ELFObjectFile<ELF64LE>> ElfOrErr =
+        toBinary<ELF64LE>(Storage, FullYamlString);
+    ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
+
+    Expected<MapVector<const Elf_Shdr *, const Elf_Shdr *>> SecToRelocMapOrErr =
+        ElfOrErr->getELFFile().getSectionAndRelocations(Matcher);
+    ASSERT_THAT_EXPECTED(SecToRelocMapOrErr, Succeeded());
+
+    // Basic verification to make sure we have the correct section types.
+    for (auto const &[Sec, RelaSec] : *SecToRelocMapOrErr) {
+      ASSERT_EQ(Sec->sh_type, ELF::SHT_PROGBITS);
+      ASSERT_EQ(RelaSec->sh_type, ELF::SHT_RELA);
+    }
+  };
+
+  auto DoCheckFails = [&](StringRef ContentsString,
+                          std::function<Expected<bool>(const Elf_Shdr &)>
+                              Matcher,
+                          const char *ErrorMessage) {
+    SmallString<0> Storage;
+    SmallString<128> FullYamlString(HeaderString);
+    FullYamlString += ContentsString;
+    Expected<ELFObjectFile<ELF64LE>> ElfOrErr =
+        toBinary<ELF64LE>(Storage, FullYamlString);
+    ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
+
+    Expected<MapVector<const Elf_Shdr *, const Elf_Shdr *>> SecToRelocMapOrErr =
+        ElfOrErr->getELFFile().getSectionAndRelocations(Matcher);
+    ASSERT_THAT_ERROR(SecToRelocMapOrErr.takeError(),
+                      FailedWithMessage(ErrorMessage));
+  };
+
+  auto DefaultMatcher = [](const Elf_Shdr &Sec) -> bool {
+    return Sec.sh_type == ELF::SHT_PROGBITS;
+  };
+
+  StringRef TwoTextSections = R"(
+Sections:
+  - Name: .text
+    Type: SHT_PROGBITS
+    Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+  - Name: .rela.text
+    Type: SHT_RELA
+    Flags: [ SHF_INFO_LINK ]
+    Info: .text
+  - Name: .text2
+    Type: SHT_PROGBITS
+    Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+  - Name: .rela.text2
+    Type: SHT_RELA
+    Flags: [ SHF_INFO_LINK ]
+    Info: .text2
+)";
+  DoCheckSucceeds(TwoTextSections, DefaultMatcher);
+
+  StringRef OneTextSection = R"(
+Sections:
+  - Name: .text
+    Type: SHT_PROGBITS
+    Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+)";
+
+  auto ErroringMatcher = [](const Elf_Shdr &Sec) -> Expected<bool> {
+    if(Sec.sh_type == ELF::SHT_PROGBITS)
+      return createError("This was supposed to fail.");
+    return false;
+  };
+
+  DoCheckFails(OneTextSection, ErroringMatcher,
+               "This was supposed to fail.");
+
+  StringRef MissingRelocatableContent = R"(
+Sections:
+  - Name: .rela.text
+    Type: SHT_RELA
+    Flags: [ SHF_INFO_LINK ]
+    Info: 0xFF
+)";
+
+  DoCheckFails(MissingRelocatableContent, DefaultMatcher,
+               "SHT_RELA section with index 1: failed to get a "
+               "relocated section: invalid section index: 255");
+}


        


More information about the llvm-commits mailing list