[yaml2obj] - Allow setting custom sh_info for RawContentSection sections.

This is for tweaking SHT_SYMTAB sections.
Their sh_info contains the (number of symbols + 1) usually.
But for creating invalid inputs for test cases it would be convenient
to allow explicitly override this field from YAML.

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

llvm-svn: 355193
diff --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h
index 91c37ec..c7bcfcb 100644
--- a/llvm/include/llvm/ObjectYAML/ELFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h
@@ -153,6 +153,7 @@
 struct RawContentSection : Section {
   yaml::BinaryRef Content;
   llvm::yaml::Hex64 Size;
+  llvm::yaml::Hex64 Info;
 
   RawContentSection() : Section(SectionKind::RawContent) {}
 
diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp
index 352048b..c374cc2 100644
--- a/llvm/lib/ObjectYAML/ELFYAML.cpp
+++ b/llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -887,6 +887,7 @@
   commonSectionMapping(IO, Section);
   IO.mapOptional("Content", Section.Content);
   IO.mapOptional("Size", Section.Size, Hex64(Section.Content.binary_size()));
+  IO.mapOptional("Info", Section.Info, Hex64(0));
 }
 
 static void sectionMapping(IO &IO, ELFYAML::NoBitsSection &Section) {
diff --git a/llvm/test/tools/obj2yaml/elf-shinfo.yaml b/llvm/test/tools/obj2yaml/elf-shinfo.yaml
new file mode 100644
index 0000000..e77fc62
--- /dev/null
+++ b/llvm/test/tools/obj2yaml/elf-shinfo.yaml
@@ -0,0 +1,20 @@
+# RUN: yaml2obj %s -o %t
+# RUN: obj2yaml %t | FileCheck %s
+
+## Check obj2yaml is able to dump sh_info field of a section.
+
+# CHECK:      - Name:            .test
+# CHECK-NEXT:   Type:            SHT_PROGBITS
+# CHECK-NEXT:   Content:         ''
+# CHECK-NEXT:   Info:            0x000000000000002A
+
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .test
+    Type:            SHT_PROGBITS
+    Info:            42
diff --git a/llvm/test/tools/yaml2obj/elf-symtab-shinfo.yaml b/llvm/test/tools/yaml2obj/elf-symtab-shinfo.yaml
new file mode 100644
index 0000000..649e568
--- /dev/null
+++ b/llvm/test/tools/yaml2obj/elf-symtab-shinfo.yaml
@@ -0,0 +1,43 @@
+## Check we are able to set sh_info field for SHT_SYMTAB sections.
+# RUN: yaml2obj %s -o %t
+# RUN: llvm-readobj -sections %t | FileCheck %s
+
+# CHECK:      Name: .symtab
+# CHECK-NEXT: Type: SHT_SYMTAB
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address:
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Size:
+# CHECK-NEXT: Link:
+# CHECK-NEXT: Info: 42
+# CHECK:      Name: .dynsym
+# CHECK-NEXT: Type: SHT_DYNSYM
+# CHECK-NEXT: Flags [
+# CHECK-NEXT:   SHF_ALLOC
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address:
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Size:
+# CHECK-NEXT: Link:
+# CHECK-NEXT: Info: 26
+ 
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:          .symtab
+    Info:          42
+    Type:          SHT_SYMTAB
+  - Name:          .dynsym
+    Info:          26
+    Type:          SHT_SYMTAB
+Symbols:
+  Global:
+    - Name: foo
+DynamicSymbols:
+  Global:
+    - Name: bar
diff --git a/llvm/test/tools/yaml2obj/elf-symtab-shtype.yaml b/llvm/test/tools/yaml2obj/elf-symtab-shtype.yaml
new file mode 100644
index 0000000..cfa5cf4
--- /dev/null
+++ b/llvm/test/tools/yaml2obj/elf-symtab-shtype.yaml
@@ -0,0 +1,21 @@
+## Check we dont crash when .symtab has type different from SHT_SYMTAB.
+# RUN: yaml2obj %s -o %t
+# RUN: llvm-readobj -sections %t | FileCheck %s
+
+## TODO: the output is still SHT_SYMTAB because we do not yet
+## support changing it.
+# CHECK:      Name: .symtab
+# CHECK-NEXT: Type: SHT_SYMTAB
+
+--- !ELF
+FileHeader:      
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:        
+  - Name:            .symtab
+    Type:            SHT_DYNAMIC
+Symbols:
+  Global:
+    - Name: foo
diff --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp
index 7f5e9a2..4d94b4b 100644
--- a/llvm/tools/obj2yaml/elf2yaml.cpp
+++ b/llvm/tools/obj2yaml/elf2yaml.cpp
@@ -458,6 +458,7 @@
     return errorToErrorCode(ContentOrErr.takeError());
   S->Content = yaml::BinaryRef(ContentOrErr.get());
   S->Size = S->Content.binary_size();
+  S->Info = Shdr->sh_info;
 
   return S.release();
 }
diff --git a/llvm/tools/yaml2obj/yaml2elf.cpp b/llvm/tools/yaml2obj/yaml2elf.cpp
index d651c92..7b5841b 100644
--- a/llvm/tools/yaml2obj/yaml2elf.cpp
+++ b/llvm/tools/yaml2obj/yaml2elf.cpp
@@ -341,13 +341,16 @@
   SHeader.sh_entsize = sizeof(Elf_Sym);
   SHeader.sh_addralign = 8;
 
-  // If .dynsym section is explicitly described in the YAML
-  // then we want to use its section address.
-  if (!IsStatic) {
-    // Take section index and ignore the SHT_NULL section.
-    unsigned SecNdx = getDotDynSymSecNo() - 1;
-    if (SecNdx < Doc.Sections.size())
-      SHeader.sh_addr = Doc.Sections[SecNdx]->Address;
+  // Get the section index ignoring the SHT_NULL section.
+  unsigned SecNdx =
+      IsStatic ? getDotSymTabSecNo() - 1 : getDotDynSymSecNo() - 1;
+  // If the symbol table section is explicitly described in the YAML
+  // then we should set the fields requested.
+  if (SecNdx < Doc.Sections.size()) {
+    ELFYAML::Section *Sec = Doc.Sections[SecNdx].get();
+    SHeader.sh_addr = Sec->Address;
+    if (auto S = dyn_cast<ELFYAML::RawContentSection>(Sec))
+      SHeader.sh_info = S->Info;
   }
 
   std::vector<Elf_Sym> Syms;
@@ -503,6 +506,7 @@
   else
     SHeader.sh_entsize = 0;
   SHeader.sh_size = Section.Size;
+  SHeader.sh_info = Section.Info;
 }
 
 static bool isMips64EL(const ELFYAML::Object &Doc) {