[yaml2obj][obj2yaml] - Support SHT_GNU_verdef (.gnu.version_d) section.

This patch adds support for parsing/dumping the .gnu.version section.

Description of the section is: https://refspecs.linuxfoundation.org/LSB_1.3.0/gLSB/gLSB/symverdefs.html

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@354574 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/llvm/ObjectYAML/ELFYAML.h b/include/llvm/ObjectYAML/ELFYAML.h
index 7205353..c7f517a 100644
--- a/include/llvm/ObjectYAML/ELFYAML.h
+++ b/include/llvm/ObjectYAML/ELFYAML.h
@@ -121,6 +121,7 @@
     RawContent,
     Relocation,
     NoBits,
+    Verdef,
     Verneed,
     Symver,
     MipsABIFlags
@@ -203,6 +204,25 @@
   }
 };
 
+struct VerdefEntry {
+  uint16_t Version;
+  uint16_t Flags;
+  uint16_t VersionNdx;
+  uint32_t Hash;
+  std::vector<StringRef> VerNames;
+};
+
+struct VerdefSection : Section {
+  std::vector<VerdefEntry> Entries;
+  llvm::yaml::Hex64 Info;
+
+  VerdefSection() : Section(SectionKind::Verdef) {}
+
+  static bool classof(const Section *S) {
+    return S->Kind == SectionKind::Verdef;
+  }
+};
+
 struct Group : Section {
   // Members of a group contain a flag and a list of section indices
   // that are part of the group.
@@ -274,6 +294,7 @@
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::ProgramHeader)
 LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<llvm::ELFYAML::Section>)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::Symbol)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::VerdefEntry)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::VernauxEntry)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::VerneedEntry)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::Relocation)
@@ -419,6 +440,10 @@
   static void mapping(IO &IO, ELFYAML::DynamicEntry &Rel);
 };
 
+template <> struct MappingTraits<ELFYAML::VerdefEntry> {
+  static void mapping(IO &IO, ELFYAML::VerdefEntry &E);
+};
+
 template <> struct MappingTraits<ELFYAML::VerneedEntry> {
   static void mapping(IO &IO, ELFYAML::VerneedEntry &E);
 };
diff --git a/lib/ObjectYAML/ELFYAML.cpp b/lib/ObjectYAML/ELFYAML.cpp
index 3eac787..e51454c 100644
--- a/lib/ObjectYAML/ELFYAML.cpp
+++ b/lib/ObjectYAML/ELFYAML.cpp
@@ -868,6 +868,12 @@
   IO.mapOptional("Size", Section.Size, Hex64(0));
 }
 
+static void sectionMapping(IO &IO, ELFYAML::VerdefSection &Section) {
+  commonSectionMapping(IO, Section);
+  IO.mapRequired("Info", Section.Info);
+  IO.mapRequired("Entries", Section.Entries);
+}
+
 static void sectionMapping(IO &IO, ELFYAML::SymverSection &Section) {
   commonSectionMapping(IO, Section);
   IO.mapRequired("Entries", Section.Entries);
@@ -956,6 +962,11 @@
       Section.reset(new ELFYAML::MipsABIFlags());
     sectionMapping(IO, *cast<ELFYAML::MipsABIFlags>(Section.get()));
     break;
+  case ELF::SHT_GNU_verdef:
+    if (!IO.outputting())
+      Section.reset(new ELFYAML::VerdefSection());
+    sectionMapping(IO, *cast<ELFYAML::VerdefSection>(Section.get()));
+    break;
   case ELF::SHT_GNU_versym:
     if (!IO.outputting())
       Section.reset(new ELFYAML::SymverSection());
@@ -1014,6 +1025,17 @@
   IO.mapRequired("Value", Rel.Val);
 }
 
+void MappingTraits<ELFYAML::VerdefEntry>::mapping(IO &IO,
+                                                  ELFYAML::VerdefEntry &E) {
+  assert(IO.getContext() && "The IO context is not initialized");
+
+  IO.mapRequired("Version", E.Version);
+  IO.mapRequired("Flags", E.Flags);
+  IO.mapRequired("VersionNdx", E.VersionNdx);
+  IO.mapRequired("Hash", E.Hash);
+  IO.mapRequired("Names", E.VerNames);
+}
+
 void MappingTraits<ELFYAML::VerneedEntry>::mapping(IO &IO,
                                                    ELFYAML::VerneedEntry &E) {
   assert(IO.getContext() && "The IO context is not initialized");
diff --git a/test/tools/obj2yaml/verdef-section.yaml b/test/tools/obj2yaml/verdef-section.yaml
new file mode 100644
index 0000000..87a283b
--- /dev/null
+++ b/test/tools/obj2yaml/verdef-section.yaml
@@ -0,0 +1,72 @@
+# RUN: yaml2obj %s -o %t
+# RUN: obj2yaml %t | FileCheck %s
+
+## Check we are able to yamalize SHT_GNU_verdef section.
+
+# CHECK:       - Name:            .gnu.version_d
+# CHECK-NEXT:     Type:            SHT_GNU_verdef
+# CHECK-NEXT:     Flags:           [ SHF_ALLOC ]
+# CHECK-NEXT:     Address:         0x0000000000000230
+# CHECK-NEXT:     Link:            .dynstr
+# CHECK-NEXT:     AddressAlign:    0x0000000000000004
+# CHECK-NEXT:     Info:            0x0000000000000004
+# CHECK-NEXT:     Entries:
+# CHECK-NEXT:       - Version:         1
+# CHECK-NEXT:         Flags:           1
+# CHECK-NEXT:         VersionNdx:      1
+# CHECK-NEXT:         Hash:            170240160
+# CHECK-NEXT:         Names:
+# CHECK-NEXT:           - dso.so.0
+# CHECK-NEXT:       - Version:         1
+# CHECK-NEXT:         Flags:           2
+# CHECK-NEXT:         VersionNdx:      2
+# CHECK-NEXT:         Hash:            108387921
+# CHECK-NEXT:         Names:
+# CHECK-NEXT:           - VERSION_1
+# CHECK-NEXT:       - Version:         1
+# CHECK-NEXT:         Flags:           3
+# CHECK-NEXT:         VersionNdx:      3
+# CHECK-NEXT:         Hash:            108387922
+# CHECK-NEXT:         Names:
+# CHECK-NEXT:           - VERSION_2
+# CHECK-NEXT:           - VERSION_3
+
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_DYN
+  Machine:         EM_X86_64
+  Entry:           0x0000000000001000
+Sections:
+  - Name:            .gnu.version_d
+    Type:            SHT_GNU_verdef
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x0000000000000230
+    Link:            .dynstr
+    AddressAlign:    0x0000000000000004
+    Info:            0x0000000000000004
+    Entries:
+      - Version:         1
+        Flags:           1
+        VersionNdx:      1
+        Hash:            170240160
+        Names:
+          - dso.so.0
+      - Version:         1
+        Flags:           2
+        VersionNdx:      2
+        Hash:            108387921
+        Names:
+          - VERSION_1
+      - Version:         1
+        Flags:           3
+        VersionNdx:      3
+        Hash:            108387922
+        Names:
+          - VERSION_2
+          - VERSION_3
+DynamicSymbols:
+  Global:
+    - Name:            foo
+...
diff --git a/test/tools/yaml2obj/verdef-section.yaml b/test/tools/yaml2obj/verdef-section.yaml
new file mode 100644
index 0000000..f81bcf1
--- /dev/null
+++ b/test/tools/yaml2obj/verdef-section.yaml
@@ -0,0 +1,69 @@
+# RUN: yaml2obj %s -o %t
+# RUN: llvm-readelf -V %t | FileCheck %s
+
+# Check we are able to handle the SHT_GNU_verdef sections.
+
+# CHECK:      SHT_GNU_verdef {
+# CHECK-NEXT:   Definition {
+# CHECK-NEXT:     Version: 1
+# CHECK-NEXT:     Flags: Base
+# CHECK-NEXT:     Index: 1
+# CHECK-NEXT:     Hash: 170240160
+# CHECK-NEXT:     Name: dso.so.0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Definition {
+# CHECK-NEXT:     Version: 1
+# CHECK-NEXT:     Flags: Weak
+# CHECK-NEXT:     Index: 2
+# CHECK-NEXT:     Hash: 108387921
+# CHECK-NEXT:     Name: VERSION_1
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Definition {
+# CHECK-NEXT:     Version: 1
+# CHECK-NEXT:     Flags: 0x3
+# CHECK-NEXT:     Index: 3
+# CHECK-NEXT:     Hash: 108387922
+# CHECK-NEXT:     Name: VERSION_2
+# CHECK-NEXT:     Predecessor: VERSION_3
+# CHECK-NEXT:   }
+# CHECK-NEXT: }
+
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_DYN
+  Machine:         EM_X86_64
+  Entry:           0x0000000000001000
+Sections:
+  - Name:            .gnu.version_d
+    Type:            SHT_GNU_verdef
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x0000000000000230
+    Link:            .dynstr
+    AddressAlign:    0x0000000000000004
+    Info:            0x0000000000000003
+    Entries:
+      - Version:         1
+        Flags:           1
+        VersionNdx:      1
+        Hash:            170240160
+        Names:
+          - dso.so.0
+      - Version:         1
+        Flags:           2
+        VersionNdx:      2
+        Hash:            108387921
+        Names:
+          - VERSION_1
+      - Version:         1
+        Flags:           3
+        VersionNdx:      3
+        Hash:            108387922
+        Names:
+          - VERSION_2
+          - VERSION_3
+DynamicSymbols:
+  Global:
+    - Name:            foo
+...
diff --git a/tools/obj2yaml/elf2yaml.cpp b/tools/obj2yaml/elf2yaml.cpp
index d593ef0..b02c25a 100644
--- a/tools/obj2yaml/elf2yaml.cpp
+++ b/tools/obj2yaml/elf2yaml.cpp
@@ -57,6 +57,7 @@
   ErrorOr<ELFYAML::RawContentSection *>
   dumpContentSection(const Elf_Shdr *Shdr);
   ErrorOr<ELFYAML::NoBitsSection *> dumpNoBitsSection(const Elf_Shdr *Shdr);
+  ErrorOr<ELFYAML::VerdefSection *> dumpVerdefSection(const Elf_Shdr *Shdr);
   ErrorOr<ELFYAML::SymverSection *> dumpSymverSection(const Elf_Shdr *Shdr);
   ErrorOr<ELFYAML::VerneedSection *> dumpVerneedSection(const Elf_Shdr *Shdr);
   ErrorOr<ELFYAML::Group *> dumpGroup(const Elf_Shdr *Shdr);
@@ -186,6 +187,13 @@
       Y->Sections.push_back(std::unique_ptr<ELFYAML::Section>(S.get()));
       break;
     }
+    case ELF::SHT_GNU_verdef: {
+      ErrorOr<ELFYAML::VerdefSection *> S = dumpVerdefSection(&Sec);
+      if (std::error_code EC = S.getError())
+        return EC;
+      Y->Sections.push_back(std::unique_ptr<ELFYAML::Section>(S.get()));
+      break;
+    }
     case ELF::SHT_GNU_versym: {
       ErrorOr<ELFYAML::SymverSection *> S = dumpSymverSection(&Sec);
       if (std::error_code EC = S.getError())
@@ -460,6 +468,56 @@
 }
 
 template <class ELFT>
+ErrorOr<ELFYAML::VerdefSection *>
+ELFDumper<ELFT>::dumpVerdefSection(const Elf_Shdr *Shdr) {
+  typedef typename ELFT::Verdef Elf_Verdef;
+  typedef typename ELFT::Verdaux Elf_Verdaux;
+
+  auto S = make_unique<ELFYAML::VerdefSection>();
+  if (std::error_code EC = dumpCommonSection(Shdr, *S))
+    return EC;
+
+  S->Info = Shdr->sh_info;
+
+  auto StringTableShdrOrErr = Obj.getSection(Shdr->sh_link);
+  if (!StringTableShdrOrErr)
+    return errorToErrorCode(StringTableShdrOrErr.takeError());
+
+  auto StringTableOrErr = Obj.getStringTable(*StringTableShdrOrErr);
+  if (!StringTableOrErr)
+    return errorToErrorCode(StringTableOrErr.takeError());
+
+  auto Contents = Obj.getSectionContents(Shdr);
+  if (!Contents)
+    return errorToErrorCode(Contents.takeError());
+
+  llvm::ArrayRef<uint8_t> Data = *Contents;
+  const uint8_t *Buf = Data.data();
+  while (Buf) {
+    const Elf_Verdef *Verdef = reinterpret_cast<const Elf_Verdef *>(Buf);
+    ELFYAML::VerdefEntry Entry;
+    Entry.Version = Verdef->vd_version;
+    Entry.Flags = Verdef->vd_flags;
+    Entry.VersionNdx = Verdef->vd_ndx;
+    Entry.Hash = Verdef->vd_hash;
+
+    const uint8_t *BufAux = Buf + Verdef->vd_aux;
+    while (BufAux) {
+      const Elf_Verdaux *Verdaux =
+          reinterpret_cast<const Elf_Verdaux *>(BufAux);
+      Entry.VerNames.push_back(
+          StringTableOrErr->drop_front(Verdaux->vda_name).data());
+      BufAux = Verdaux->vda_next ? BufAux + Verdaux->vda_next : nullptr;
+    }
+
+    S->Entries.push_back(Entry);
+    Buf = Verdef->vd_next ? Buf + Verdef->vd_next : nullptr;
+  }
+
+  return S.release();
+}
+
+template <class ELFT>
 ErrorOr<ELFYAML::SymverSection *>
 ELFDumper<ELFT>::dumpSymverSection(const Elf_Shdr *Shdr) {
   typedef typename ELFT::Half Elf_Half;
diff --git a/tools/yaml2obj/yaml2elf.cpp b/tools/yaml2obj/yaml2elf.cpp
index 4e51744..351b734 100644
--- a/tools/yaml2obj/yaml2elf.cpp
+++ b/tools/yaml2obj/yaml2elf.cpp
@@ -164,6 +164,9 @@
                            const ELFYAML::VerneedSection &Section,
                            ContiguousBlobAccumulator &CBA);
   bool writeSectionContent(Elf_Shdr &SHeader,
+                           const ELFYAML::VerdefSection &Section,
+                           ContiguousBlobAccumulator &CBA);
+  bool writeSectionContent(Elf_Shdr &SHeader,
                            const ELFYAML::MipsABIFlags &Section,
                            ContiguousBlobAccumulator &CBA);
   void writeSectionContent(Elf_Shdr &SHeader,
@@ -311,6 +314,8 @@
       writeSectionContent(SHeader, *S, CBA);
     } else if (auto S = dyn_cast<ELFYAML::VerneedSection>(Sec.get())) {
       writeSectionContent(SHeader, *S, CBA);
+    } else if (auto S = dyn_cast<ELFYAML::VerdefSection>(Sec.get())) {
+      writeSectionContent(SHeader, *S, CBA);
     } else
       llvm_unreachable("Unknown section type");
 
@@ -587,6 +592,51 @@
 
 template <class ELFT>
 bool ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
+                                         const ELFYAML::VerdefSection &Section,
+                                         ContiguousBlobAccumulator &CBA) {
+  typedef typename ELFT::Verdef Elf_Verdef;
+  typedef typename ELFT::Verdaux Elf_Verdaux;
+  raw_ostream &OS =
+      CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);
+
+  uint64_t AuxCnt = 0;
+  for (size_t I = 0; I < Section.Entries.size(); ++I) {
+    const ELFYAML::VerdefEntry &E = Section.Entries[I];
+
+    Elf_Verdef VerDef;
+    VerDef.vd_version = E.Version;
+    VerDef.vd_flags = E.Flags;
+    VerDef.vd_ndx = E.VersionNdx;
+    VerDef.vd_hash = E.Hash;
+    VerDef.vd_aux = sizeof(Elf_Verdef);
+    VerDef.vd_cnt = E.VerNames.size();
+    if (I == Section.Entries.size() - 1)
+      VerDef.vd_next = 0;
+    else
+      VerDef.vd_next =
+          sizeof(Elf_Verdef) + E.VerNames.size() * sizeof(Elf_Verdaux);
+    OS.write((const char *)&VerDef, sizeof(Elf_Verdef));
+
+    for (size_t J = 0; J < E.VerNames.size(); ++J, ++AuxCnt) {
+      Elf_Verdaux VernAux;
+      VernAux.vda_name = DotDynstr.getOffset(E.VerNames[J]);
+      if (J == E.VerNames.size() - 1)
+        VernAux.vda_next = 0;
+      else
+        VernAux.vda_next = sizeof(Elf_Verdaux);
+      OS.write((const char *)&VernAux, sizeof(Elf_Verdaux));
+    }
+  }
+
+  SHeader.sh_size = Section.Entries.size() * sizeof(Elf_Verdef) +
+                    AuxCnt * sizeof(Elf_Verdaux);
+  SHeader.sh_info = Section.Info;
+
+  return true;
+}
+
+template <class ELFT>
+bool ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
                                          const ELFYAML::VerneedSection &Section,
                                          ContiguousBlobAccumulator &CBA) {
  typedef typename ELFT::Verneed Elf_Verneed;
@@ -746,16 +796,19 @@
   // Add the dynamic symbol names to .dynstr section.
   AddSymbols(DotDynstr, Doc.DynamicSymbols);
 
-  // SHT_GNU_verneed section also adds strings to .dynstr section.
+  // SHT_GNU_verdef and SHT_GNU_verneed sections might also
+  // add strings to .dynstr section.
   for (const std::unique_ptr<ELFYAML::Section> &Sec : Doc.Sections) {
-    auto VerNeed = dyn_cast<ELFYAML::VerneedSection>(Sec.get());
-    if (!VerNeed)
-      continue;
-
-    for (const ELFYAML::VerneedEntry &VE : VerNeed->VerneedV) {
-      DotDynstr.add(VE.File);
-      for (const ELFYAML::VernauxEntry &Aux : VE.AuxV)
-        DotDynstr.add(Aux.Name);
+    if (auto VerNeed = dyn_cast<ELFYAML::VerneedSection>(Sec.get())) {
+      for (const ELFYAML::VerneedEntry &VE : VerNeed->VerneedV) {
+        DotDynstr.add(VE.File);
+        for (const ELFYAML::VernauxEntry &Aux : VE.AuxV)
+          DotDynstr.add(Aux.Name);
+      }
+    } else if (auto VerDef = dyn_cast<ELFYAML::VerdefSection>(Sec.get())) {
+      for (const ELFYAML::VerdefEntry &E : VerDef->Entries)
+        for (StringRef Name : E.VerNames)
+          DotDynstr.add(Name);
     }
   }