[llvm] aefec9e - [obj2yaml] - Refactor how we dump sections. NFCI.

Georgii Rymar via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 26 04:04:27 PDT 2020


Author: Georgii Rymar
Date: 2020-03-26T14:04:07+03:00
New Revision: aefec9ed77f63db832b1235d427b439c04759873

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

LOG: [obj2yaml] - Refactor how we dump sections. NFCI.

This is a NFC splitted from D75342.

Previously obj2yaml never dumped a normal SHT_NULL section (i.e. when it is just zeroed)
or non-allocatable SHT_STRTAB/SHT_SYMTAB/SHT_DYNSYM sections.

This patch does not change the output, but it changes the logic so that we now dump these
sections, and them remove them later. It allows us to create and work with our internal representation
of sections, i.e. to work with the vector of Chunks, what looks cleaner.

It is used by D75342 and also should help us to support dumping a content that does not
belong to a section (i.e. to dump some data as `Fill` chunks).

Differential revision: https://reviews.llvm.org/D76684

Added: 
    

Modified: 
    llvm/include/llvm/ObjectYAML/ELFYAML.h
    llvm/tools/obj2yaml/elf2yaml.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h
index 44f5d7cd069e..252f0c8e212e 100644
--- a/llvm/include/llvm/ObjectYAML/ELFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h
@@ -177,6 +177,9 @@ struct Section : public Chunk {
   // When they are, this flag is used to signal about that.
   bool IsImplicit;
 
+  // Holds the original section index.
+  unsigned OriginalSecNdx;
+
   Section(ChunkKind Kind, bool IsImplicit = false)
       : Chunk(Kind), IsImplicit(IsImplicit) {}
 

diff  --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp
index ac3eefdeaace..bf6d9657e76e 100644
--- a/llvm/tools/obj2yaml/elf2yaml.cpp
+++ b/llvm/tools/obj2yaml/elf2yaml.cpp
@@ -88,6 +88,10 @@ class ELFDumper {
   Expected<ELFYAML::MipsABIFlags *> dumpMipsABIFlags(const Elf_Shdr *Shdr);
   Expected<ELFYAML::StackSizesSection *>
   dumpStackSizesSection(const Elf_Shdr *Shdr);
+  Expected<ELFYAML::RawContentSection *>
+  dumpPlaceholderSection(const Elf_Shdr *Shdr);
+
+  bool shouldPrintSection(const ELFYAML::Section &S, const Elf_Shdr &SHdr);
 
 public:
   ELFDumper(const object::ELFFile<ELFT> &O);
@@ -112,6 +116,12 @@ ELFDumper<ELFT>::getUniquedSectionName(const Elf_Shdr *Sec) {
   if (!NameOrErr)
     return NameOrErr;
   StringRef Name = *NameOrErr;
+  // In some specific cases we might have more than one section without a
+  // name (sh_name == 0). It normally doesn't happen, but when we have this case
+  // it doesn't make sense to uniquify their names and add noise to the output.
+  if (Name.empty())
+    return "";
+
   std::string &Ret = SectionNames[SecIndex];
 
   auto It = UsedSectionNames.insert({Name, 0});
@@ -157,6 +167,32 @@ ELFDumper<ELFT>::getUniquedSymbolName(const Elf_Sym *Sym, StringRef StrTable,
   return Name;
 }
 
+template <class ELFT>
+bool ELFDumper<ELFT>::shouldPrintSection(const ELFYAML::Section &S,
+                                         const Elf_Shdr &SHdr) {
+  // We only print the SHT_NULL section at index 0 when it
+  // has at least one non-null field, because yaml2obj
+  // normally creates the zero section at index 0 implicitly.
+  if (S.Type == ELF::SHT_NULL && (&SHdr == &Sections[0])) {
+    const uint8_t *Begin = reinterpret_cast<const uint8_t *>(&SHdr);
+    const uint8_t *End = Begin + sizeof(Elf_Shdr);
+    return std::find_if(Begin, End, [](uint8_t V) { return V != 0; }) != End;
+  }
+
+  // Normally we use "Symbols:" and "DynamicSymbols:" to describe contents of
+  // symbol tables. We also build and emit corresponding string tables
+  // implicitly. But sometimes it is important to preserve positions and virtual
+  // addresses of allocatable sections, e.g. for creating program headers.
+  // Generally we are trying to reduce noise in the YAML output. Because
+  // of that we do not print non-allocatable versions of such sections and
+  // assume they are placed at the end.
+  if (S.Type == ELF::SHT_STRTAB || S.Type == ELF::SHT_SYMTAB ||
+      S.Type == ELF::SHT_DYNSYM)
+    return S.Flags.getValueOr(ELFYAML::ELF_SHF(0)) & ELF::SHF_ALLOC;
+
+  return true;
+}
+
 template <class ELFT> Expected<ELFYAML::Object *> ELFDumper<ELFT>::dump() {
   auto Y = std::make_unique<ELFYAML::Object>();
 
@@ -227,15 +263,34 @@ template <class ELFT> Expected<ELFYAML::Object *> ELFDumper<ELFT>::dump() {
       return std::move(E);
   }
 
-  if (Expected<std::vector<std::unique_ptr<ELFYAML::Chunk>>> ChunksOrErr =
-          dumpSections())
-    Y->Chunks = std::move(*ChunksOrErr);
-  else
+  // We dump all sections first. It is simple and allows us to verify that all
+  // sections are valid and also to generalize the code. But we are not going to
+  // keep all of them in the final output (see comments for
+  // 'shouldPrintSection()'). Undesired chunks will be removed later.
+  Expected<std::vector<std::unique_ptr<ELFYAML::Chunk>>> ChunksOrErr =
+      dumpSections();
+  if (!ChunksOrErr)
     return ChunksOrErr.takeError();
 
+  std::vector<std::unique_ptr<ELFYAML::Chunk>> Chunks = std::move(*ChunksOrErr);
+  llvm::erase_if(Chunks, [this](const std::unique_ptr<ELFYAML::Chunk> &C) {
+    const ELFYAML::Section &S = cast<ELFYAML::Section>(*C.get());
+    return !shouldPrintSection(S, Sections[S.OriginalSecNdx]);
+  });
+
+  Y->Chunks = std::move(Chunks);
   return Y.release();
 }
 
+template <class ELFT>
+Expected<ELFYAML::RawContentSection *>
+ELFDumper<ELFT>::dumpPlaceholderSection(const Elf_Shdr *Shdr) {
+  auto S = std::make_unique<ELFYAML::RawContentSection>();
+  if (Error E = dumpCommonSection(Shdr, *S.get()))
+    return std::move(E);
+  return S.release();
+}
+
 template <class ELFT>
 Expected<std::vector<std::unique_ptr<ELFYAML::Chunk>>>
 ELFDumper<ELFT>::dumpSections() {
@@ -288,6 +343,13 @@ ELFDumper<ELFT>::dumpSections() {
     case ELF::SHT_LLVM_CALL_GRAPH_PROFILE:
       return
           [this](const Elf_Shdr *S) { return dumpCallGraphProfileSection(S); };
+    case ELF::SHT_STRTAB:
+    case ELF::SHT_SYMTAB:
+    case ELF::SHT_DYNSYM:
+      // The contents of these sections are described by other parts of the YAML
+      // file. But we still want to dump them, because their properties can be
+      // important. See comments for 'shouldPrintSection()' for more details.
+      return [this](const Elf_Shdr *S) { return dumpPlaceholderSection(S); };
     default:
       return nullptr;
     }
@@ -303,37 +365,6 @@ ELFDumper<ELFT>::dumpSections() {
       continue;
     }
 
-    if (Sec.sh_type == ELF::SHT_STRTAB || Sec.sh_type == ELF::SHT_SYMTAB ||
-        Sec.sh_type == ELF::SHT_DYNSYM) {
-      // The contents of these sections are described by other parts of the YAML
-      // file. We still dump them so that their positions in the section header
-      // table are correctly recorded. We only dump allocatable section because
-      // their positions and addresses are important, e.g. for creating program
-      // headers. Some sections, like .symtab or .strtab normally are not
-      // allocatable and do not have virtual addresses. We want to avoid noise
-      // in the YAML output and assume that they are placed at the end.
-      if (Sec.sh_flags & ELF::SHF_ALLOC) {
-        auto S = std::make_unique<ELFYAML::RawContentSection>();
-        if (Error E = dumpCommonSection(&Sec, *S.get()))
-          return std::move(E);
-        if (Error E = Add(S.release()))
-          return std::move(E);
-      }
-      continue;
-    }
-
-    if (Sec.sh_type == ELF::SHT_NULL) {
-      // We only dump the SHT_NULL section at index 0 when it
-      // has at least one non-null field, because yaml2obj
-      // normally creates the zero section at index 0 implicitly.
-      if (&Sec == &Sections[0]) {
-        const uint8_t *Begin = reinterpret_cast<const uint8_t *>(&Sec);
-        const uint8_t *End = Begin + sizeof(Elf_Shdr);
-        if (std::find_if(Begin, End, [](uint8_t V) { return V != 0; }) == End)
-          continue;
-      }
-    }
-
     // Recognize some special SHT_PROGBITS sections by name.
     if (Sec.sh_type == ELF::SHT_PROGBITS) {
       auto NameOrErr = getUniquedSectionName(&Sec);
@@ -484,6 +515,8 @@ Error ELFDumper<ELFT>::dumpCommonSection(const Elf_Shdr *Shdr,
   if (Shdr->sh_entsize != getDefaultShEntSize<ELFT>(S.Type))
     S.EntSize = static_cast<llvm::yaml::Hex64>(Shdr->sh_entsize);
 
+  S.OriginalSecNdx = Shdr - &Sections[0];
+
   auto NameOrErr = getUniquedSectionName(Shdr);
   if (!NameOrErr)
     return NameOrErr.takeError();


        


More information about the llvm-commits mailing list