[llvm] dab9917 - [yaml2obj][obj2yaml] - Add a support for SHT_ARM_EXIDX section.

Georgii Rymar via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 28 01:46:10 PDT 2020


Author: Georgii Rymar
Date: 2020-09-28T11:45:49+03:00
New Revision: dab991716483f2b80bf8dbf8e7ba26ba3d49855d

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

LOG: [yaml2obj][obj2yaml] - Add a support for SHT_ARM_EXIDX section.

This adds the support for SHT_ARM_EXIDX sections to obj2yaml/yaml2obj tools.

SHT_ARM_EXIDX is a ARM specific index table filled with entries.
Each entry consists of two 4-bytes values (words).
(https://developer.arm.com/documentation/ihi0038/c/?lang=en#index-table-entries)

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

Added: 
    llvm/test/tools/obj2yaml/ELF/arm-exidx-section.yaml
    llvm/test/tools/yaml2obj/ELF/arm-exidx-section.yaml

Modified: 
    llvm/include/llvm/ObjectYAML/ELFYAML.h
    llvm/lib/ObjectYAML/ELFEmitter.cpp
    llvm/lib/ObjectYAML/ELFYAML.cpp
    llvm/test/tools/llvm-readobj/ELF/ARM/unwind-non-relocatable.test
    llvm/tools/obj2yaml/elf2yaml.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h
index 2439b4e89986..17ba8f9fda21 100644
--- a/llvm/include/llvm/ObjectYAML/ELFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h
@@ -153,6 +153,7 @@ struct Chunk {
     StackSizes,
     SymtabShndxSection,
     Symver,
+    ARMIndexTable,
     MipsABIFlags,
     Addrsig,
     Fill,
@@ -493,6 +494,23 @@ struct SymtabShndxSection : Section {
   }
 };
 
+struct ARMIndexTableEntry {
+  llvm::yaml::Hex32 Offset;
+  llvm::yaml::Hex32 Value;
+};
+
+struct ARMIndexTableSection : Section {
+  Optional<std::vector<ARMIndexTableEntry>> Entries;
+  Optional<yaml::BinaryRef> Content;
+  Optional<llvm::yaml::Hex64> Size;
+
+  ARMIndexTableSection() : Section(ChunkKind::ARMIndexTable) {}
+
+  static bool classof(const Chunk *S) {
+    return S->Kind == ChunkKind::ARMIndexTable;
+  }
+};
+
 // Represents .MIPS.abiflags section
 struct MipsABIFlags : Section {
   llvm::yaml::Hex16 Version;
@@ -575,6 +593,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::VerneedEntry)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::Relocation)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::SectionOrType)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::SectionName)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::ARMIndexTableEntry)
 
 namespace llvm {
 namespace yaml {
@@ -757,6 +776,10 @@ template <> struct MappingTraits<ELFYAML::Relocation> {
   static void mapping(IO &IO, ELFYAML::Relocation &Rel);
 };
 
+template <> struct MappingTraits<ELFYAML::ARMIndexTableEntry> {
+  static void mapping(IO &IO, ELFYAML::ARMIndexTableEntry &E);
+};
+
 template <> struct MappingTraits<std::unique_ptr<ELFYAML::Chunk>> {
   static void mapping(IO &IO, std::unique_ptr<ELFYAML::Chunk> &C);
   static StringRef validate(IO &io, std::unique_ptr<ELFYAML::Chunk> &C);

diff  --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp
index b1adf03074a1..04542ccaecff 100644
--- a/llvm/lib/ObjectYAML/ELFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp
@@ -259,6 +259,9 @@ template <class ELFT> class ELFState {
   void writeSectionContent(Elf_Shdr &SHeader,
                            const ELFYAML::VerdefSection &Section,
                            ContiguousBlobAccumulator &CBA);
+  void writeSectionContent(Elf_Shdr &SHeader,
+                           const ELFYAML::ARMIndexTableSection &Section,
+                           ContiguousBlobAccumulator &CBA);
   void writeSectionContent(Elf_Shdr &SHeader,
                            const ELFYAML::MipsABIFlags &Section,
                            ContiguousBlobAccumulator &CBA);
@@ -696,6 +699,8 @@ void ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
       writeSectionContent(SHeader, *S, CBA);
     } else if (auto S = dyn_cast<ELFYAML::Group>(Sec)) {
       writeSectionContent(SHeader, *S, CBA);
+    } else if (auto S = dyn_cast<ELFYAML::ARMIndexTableSection>(Sec)) {
+      writeSectionContent(SHeader, *S, CBA);
     } else if (auto S = dyn_cast<ELFYAML::MipsABIFlags>(Sec)) {
       writeSectionContent(SHeader, *S, CBA);
     } else if (auto S = dyn_cast<ELFYAML::NoBitsSection>(Sec)) {
@@ -1514,6 +1519,25 @@ void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
                     AuxCnt * sizeof(Elf_Vernaux);
 }
 
+template <class ELFT>
+void ELFState<ELFT>::writeSectionContent(
+    Elf_Shdr &SHeader, const ELFYAML::ARMIndexTableSection &Section,
+    ContiguousBlobAccumulator &CBA) {
+  if (Section.Content || Section.Size) {
+    SHeader.sh_size = writeContent(CBA, Section.Content, Section.Size);
+    return;
+  }
+
+  if (!Section.Entries)
+    return;
+
+  for (const ELFYAML::ARMIndexTableEntry &E : *Section.Entries) {
+    CBA.write<uint32_t>(E.Offset, ELFT::TargetEndianness);
+    CBA.write<uint32_t>(E.Value, ELFT::TargetEndianness);
+  }
+  SHeader.sh_size = Section.Entries->size() * 8;
+}
+
 template <class ELFT>
 void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
                                          const ELFYAML::MipsABIFlags &Section,

diff  --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp
index 03799f4545d4..a86172418c1e 100644
--- a/llvm/lib/ObjectYAML/ELFYAML.cpp
+++ b/llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -14,6 +14,7 @@
 #include "llvm/ADT/MapVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Support/ARMEHABI.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/MipsABIFlags.h"
@@ -1267,6 +1268,13 @@ void MappingTraits<ELFYAML::SectionName>::mapping(
   IO.mapRequired("Section", sectionName.Section);
 }
 
+static void sectionMapping(IO &IO, ELFYAML::ARMIndexTableSection &Section) {
+  commonSectionMapping(IO, Section);
+  IO.mapOptional("Content", Section.Content);
+  IO.mapOptional("Size", Section.Size);
+  IO.mapOptional("Entries", Section.Entries);
+}
+
 static void sectionMapping(IO &IO, ELFYAML::MipsABIFlags &Section) {
   commonSectionMapping(IO, Section);
   IO.mapOptional("Version", Section.Version, Hex16(0));
@@ -1287,6 +1295,12 @@ static void sectionMapping(IO &IO, ELFYAML::MipsABIFlags &Section) {
   IO.mapOptional("Flags2", Section.Flags2, Hex32(0));
 }
 
+static StringRef getStringValue(IO &IO, const char *Key) {
+  StringRef Val;
+  IO.mapRequired(Key, Val);
+  return Val;
+}
+
 void MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::mapping(
     IO &IO, std::unique_ptr<ELFYAML::Chunk> &Section) {
   ELFYAML::ELF_SHT Type;
@@ -1296,9 +1310,7 @@ void MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::mapping(
     // When the Type string does not have a "SHT_" prefix, we know it is not a
     // description of a regular ELF output section. Currently, we have one
     // special type named "Fill". See comments for Fill.
-    StringRef StrType;
-    IO.mapRequired("Type", StrType);
-    if (StrType == "Fill") {
+    if (getStringValue(IO, "Type") == "Fill") {
       Section.reset(new ELFYAML::Fill());
       fillMapping(IO, *cast<ELFYAML::Fill>(Section.get()));
       return;
@@ -1315,6 +1327,13 @@ void MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::mapping(
     return;
   }
 
+  if (Obj.getMachine() == ELF::EM_ARM && Type == ELF::SHT_ARM_EXIDX) {
+    if (!IO.outputting())
+      Section.reset(new ELFYAML::ARMIndexTableSection());
+    sectionMapping(IO, *cast<ELFYAML::ARMIndexTableSection>(Section.get()));
+    return;
+  }
+
   switch (Type) {
   case ELF::SHT_DYNAMIC:
     if (!IO.outputting())
@@ -1580,6 +1599,21 @@ StringRef MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::validate(
     return {};
   }
 
+  if (const auto *IT = dyn_cast<ELFYAML::ARMIndexTableSection>(C.get())) {
+    if (IT->Content || IT->Size) {
+      if (IT->Size && IT->Content &&
+          (uint64_t)*IT->Size < IT->Content->binary_size())
+        return "\"Size\" must be greater than or equal to the content "
+               "size";
+
+      if (IT->Entries)
+        return "\"Entries\" cannot be used with \"Content\" or \"Size\"";
+      return {};
+    }
+
+    return {};
+  }
+
   return {};
 }
 
@@ -1692,6 +1726,20 @@ void MappingTraits<ELFYAML::Relocation>::mapping(IO &IO,
   IO.mapOptional("Addend", Rel.Addend, (ELFYAML::YAMLIntUInt)0);
 }
 
+void MappingTraits<ELFYAML::ARMIndexTableEntry>::mapping(
+    IO &IO, ELFYAML::ARMIndexTableEntry &E) {
+  assert(IO.getContext() && "The IO context is not initialized");
+  IO.mapRequired("Offset", E.Offset);
+
+  StringRef CantUnwind = "EXIDX_CANTUNWIND";
+  if (IO.outputting() && (uint32_t)E.Value == ARM::EHABI::EXIDX_CANTUNWIND)
+    IO.mapRequired("Value", CantUnwind);
+  else if (!IO.outputting() && getStringValue(IO, "Value") == CantUnwind)
+    E.Value = ARM::EHABI::EXIDX_CANTUNWIND;
+  else
+    IO.mapRequired("Value", E.Value);
+}
+
 void MappingTraits<ELFYAML::Object>::mapping(IO &IO, ELFYAML::Object &Object) {
   assert(!IO.getContext() && "The IO context is initialized already");
   IO.setContext(&Object);

diff  --git a/llvm/test/tools/llvm-readobj/ELF/ARM/unwind-non-relocatable.test b/llvm/test/tools/llvm-readobj/ELF/ARM/unwind-non-relocatable.test
index 3ceeab1f2d95..4748a044c1a3 100644
--- a/llvm/test/tools/llvm-readobj/ELF/ARM/unwind-non-relocatable.test
+++ b/llvm/test/tools/llvm-readobj/ELF/ARM/unwind-non-relocatable.test
@@ -65,20 +65,19 @@ Sections:
   - Name:    .ARM.exidx
     Type:    SHT_ARM_EXIDX
     Address: 0x24C
-    ContentArray: [
-## Entry 1. Address of .ARM.exidx (0x24C) + entry offset (0) + 0x7fffffe4 == 0x230 (func1).
-                    0xE4, 0xFF, 0xFF, 0x7F, ## Word(0) = 0x7fffffe4 (31 bit).
-                    0xB0, 0xB0, 0xB0, 0x80, ## Word(1): arbitrary opcodes.
-## Entry 2. Address of .ARM.exidx (0x24C) + entry offset (8) + 0x7fffffe0 == 0x234 (func2).
-                    0xE0, 0xFF, 0xFF, 0x7F, ## Word(0) = 0x7fffffe0 (31 bit).
-                    0x80, 0x84, 0x9B, 0x80, ## Word(1): arbitrary opcodes.
-## Entry 3. Address of .ARM.exidx (0x24C) + entry offset (16) + 0x7fffffec == 0x248 (func2).
-                    0xEC, 0xFF, 0xFF, 0x7F, ## Word(0) = 0x7fffffec (31 bit).
-                    0xB0, 0xB0, 0xB0, 0x80, ## Word(1): arbitrary opcodes.
-## Entry 4. Address of .ARM.exidx (0x24C) + entry offset (24) + 0x7fffffe8 == 0x24C.
-                    0xE8, 0xFF, 0xFF, 0x7F, ## Word(0) = 0x7fffffe8 (31 bit).
-                    0x01, 0x00, 0x00, 0x00  ## Word(1) == EXIDX_CANTUNWIND
-                  ]
+    Entries:
+## Address of .ARM.exidx (0x24C) + entry offset (0) + 0x7fffffe4 (31 bit) == 0x230 (func1).
+      - Offset: 0x7FFFFFE4
+        Value:  0x80B0B0B0 ## arbitrary opcodes.
+## Address of .ARM.exidx (0x24C) + entry offset (8) + 0x7fffffe0 (31 bit) == 0x234 (func2).
+      - Offset: 0x7FFFFFE0
+        Value:  0x809B8480 ## arbitrary opcodes.
+## Address of .ARM.exidx (0x24C) + entry offset (16) + 0x7fffffec (31 bit) == 0x248 (func2).
+      - Offset: 0x7FFFFFEC
+        Value:  0x80B0B0B0 ## arbitrary opcodes.
+## Address of .ARM.exidx (0x24C) + entry offset (24) + 0x7fffffe8 (31 bit) == 0x24C.
+      - Offset: 0x7FFFFFE8
+        Value:  EXIDX_CANTUNWIND
 Symbols:
   - Name:    func1
     Type:    STT_FUNC

diff  --git a/llvm/test/tools/obj2yaml/ELF/arm-exidx-section.yaml b/llvm/test/tools/obj2yaml/ELF/arm-exidx-section.yaml
new file mode 100644
index 000000000000..a68b9a553c6a
--- /dev/null
+++ b/llvm/test/tools/obj2yaml/ELF/arm-exidx-section.yaml
@@ -0,0 +1,107 @@
+## Check how obj2yaml dumps the SHT_ARM_EXIDX section.
+
+## For a valid section, obj2yaml emits the "Entries" key.
+## This checks that we respect data endianness and recognize the
+## EXIDX_CANTUNWIND (0x1) special value properly.
+
+# RUN: yaml2obj --docnum=1 -DENCODE=LSB %s -o %t.le.so
+# RUN: obj2yaml %t.le.so | FileCheck %s --check-prefix=LE
+# RUN: yaml2obj --docnum=1 -DENCODE=MSB %s -o %t.be.so
+# RUN: obj2yaml %t.be.so | FileCheck %s --check-prefix=BE
+
+# LE:      - Name: .ARM.exidx
+# LE-NEXT:   Type: SHT_ARM_EXIDX
+# LE-NEXT:   Entries:
+# LE-NEXT:     - Offset: 0xDDCCBBAA
+# LE-NEXT:       Value:  0x01000000
+# LE-NEXT:     - Offset: 0x9988FFEE
+# LE-NEXT:       Value:  EXIDX_CANTUNWIND
+# LE-NEXT: ...
+
+# BE:      - Name: .ARM.exidx
+# BE-NEXT:   Type: SHT_ARM_EXIDX
+# BE-NEXT:   Entries:
+# BE-NEXT:     - Offset: 0xAABBCCDD
+# BE-NEXT:       Value:  EXIDX_CANTUNWIND
+# BE-NEXT:     - Offset: 0xEEFF8899
+# BE-NEXT:       Value:  0x01000000
+# BE-NEXT: ...
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2[[ENCODE=LSB]]
+  Type:    ET_DYN
+  Machine: EM_ARM
+Sections:
+  - Name:    .ARM.exidx
+    Type:    SHT_ARM_EXIDX
+## 4 words: <arbitrary>, EXIDX_CANTUNWIND in big-endian,
+##          <arbitrary> and EXIDX_CANTUNWIND in little-endian.
+    Content: "AABBCCDD00000001EEFF889901000000"
+    Size:    [[SIZE=<none>]]
+
+## Check that we dump the content of a truncated SHT_ARM_EXIDX section
+## using the "Content" key.
+# RUN: yaml2obj --docnum=1 -DSIZE=17 %s -o %t.invalid-size.so
+# RUN: obj2yaml %t.invalid-size.so | FileCheck %s --check-prefix=INVALID-SIZE
+
+# INVALID-SIZE:      - Name:    .ARM.exidx
+# INVALID-SIZE-NEXT:   Type:    SHT_ARM_EXIDX
+# INVALID-SIZE-NEXT:   Content: AABBCCDD00000001EEFF88990100000000
+# INVALID-SIZE-NEXT: ...
+
+## Check how we dump an empty SHT_ARM_EXIDX section.
+# RUN: yaml2obj --docnum=2 %s -o %t.empty.so
+# RUN: obj2yaml %t.empty.so | FileCheck %s --check-prefix=EMPTY
+
+# EMPTY:      - Name: .ARM.exidx
+# EMPTY-NEXT:     Type:    SHT_ARM_EXIDX
+# EMPTY-NEXT:     Entries: []
+# EMPTY-NEXT: ...
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_DYN
+  Machine: EM_ARM
+Sections:
+  - Name: .ARM.exidx
+    Type: SHT_ARM_EXIDX
+
+## Check how we dump the SHT_ARM_EXIDX (0x70000001) section when
+## the machine type is not EM_ARM. It is dumped as a regular
+## section of an unknown type.
+
+# RUN: yaml2obj --docnum=3 %s -o %t.not-arm.so
+# RUN: obj2yaml %t.not-arm.so | FileCheck %s --check-prefix=NOT-ARM
+
+# RUN: yaml2obj --docnum=3 -DMACHINE=EM_ARM %s -o %t.arm.so
+# RUN: obj2yaml %t.arm.so | FileCheck %s --check-prefix=ARM
+
+# NOT-ARM:      Sections:
+# NOT-ARM-NEXT:   - Name:    .ARM.exidx
+# NOT-ARM-NEXT:     Type:    0x70000001
+# NOT-ARM-NEXT:     Content: AABBCCDD11223344
+# NOT-ARM-NEXT: ...
+
+# ARM:      - Name: .ARM.exidx
+# ARM-NEXT:   Type: SHT_ARM_EXIDX
+# ARM-NEXT:   Entries:
+# ARM-NEXT:     - Offset: 0xDDCCBBAA
+# ARM-NEXT:       Value:  0x44332211
+# ARM-NEXT: ...
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_DYN
+  Machine: [[MACHINE=<none>]]
+Sections:
+  - Name:    .ARM.exidx
+    Type:    SHT_PROGBITS
+    ShType:  0x70000001 ## SHT_ARM_EXIDX
+## An arbitrary valid content.
+    Content: "AABBCCDD11223344"

diff  --git a/llvm/test/tools/yaml2obj/ELF/arm-exidx-section.yaml b/llvm/test/tools/yaml2obj/ELF/arm-exidx-section.yaml
new file mode 100644
index 000000000000..4b3d96caa23e
--- /dev/null
+++ b/llvm/test/tools/yaml2obj/ELF/arm-exidx-section.yaml
@@ -0,0 +1,129 @@
+## Test how we create SHT_ARM_EXIDX sections.
+
+## Test that the content of SHT_ARM_EXIDX sections,
+## generated for 32/64-bit little/big endian targets is correct.
+## Also check that we can use a special EXIDX_CANTUNWIND (0x1) value for a Value field of an entry.
+# RUN: yaml2obj --docnum=1 -DENCODE=LSB -DCLASS=64 %s -o %t.le64
+# RUN: llvm-readobj --sections --section-data %t.le64 | FileCheck %s --check-prefixes=DEFAULT,LE
+# RUN: yaml2obj --docnum=1 -DENCODE=LSB -DCLASS=32 %s -o %t.le32
+# RUN: llvm-readobj --sections --section-data %t.le32 | FileCheck %s --check-prefixes=DEFAULT,LE
+# RUN: yaml2obj --docnum=1 -DENCODE=MSB -DCLASS=64 %s -o %t.be64
+# RUN: llvm-readobj --sections --section-data %t.be64 | FileCheck %s --check-prefixes=DEFAULT,BE
+# RUN: yaml2obj --docnum=1 -DENCODE=MSB -DCLASS=32 %s -o %t.be32
+# RUN: llvm-readobj --sections --section-data %t.be32 | FileCheck %s --check-prefixes=DEFAULT,BE
+
+# DEFAULT:      Name: .ARM.exidx (1)
+# DEFAULT-NEXT: Type: SHT_ARM_EXIDX (0x70000001)
+# DEFAULT-NEXT: Flags [ (0x0)
+# DEFAULT-NEXT: ]
+# DEFAULT-NEXT: Address: 0x0
+# DEFAULT-NEXT: Offset: 0x{{.*}}
+# DEFAULT-NEXT: Size: 16
+# DEFAULT-NEXT: Link: 0
+# DEFAULT-NEXT: Info: 0
+# DEFAULT-NEXT: AddressAlignment: 0
+# DEFAULT-NEXT: EntrySize: 0
+# DEFAULT-NEXT: SectionData (
+# LE-NEXT:       0000: DDCCBBAA 44332211 9988FFEE 01000000  |
+# BE-NEXT:       0000: AABBCCDD 11223344 EEFF8899 00000001  |
+# DEFAULT-NEXT: )
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS[[CLASS=64]]
+  Data:    ELFDATA2[[ENCODE=LSB]]
+  Type:    ET_DYN
+  Machine: [[MACHINE=EM_ARM]]
+Sections:
+  - Name: .ARM.exidx
+    Type: SHT_ARM_EXIDX
+    Entries:
+      - Offset: 0xAABBCCDD
+        Value:  0x11223344
+      - Offset: 0xEEFF8899
+        Value:  EXIDX_CANTUNWIND
+
+## Check we only recognize the SHT_ARM_EXIDX section type when machine type is EM_ARM.
+# RUN: not yaml2obj --docnum=1 -DMACHINE=EM_NONE %s 2>&1 | FileCheck %s --check-prefix=UNKNOWN
+
+# UNKNOWN:      error: invalid hex32 number
+# UNKNOWN-NEXT:  Type: SHT_ARM_EXIDX
+
+## Check we can set arbitrary section properties for a SHT_ARM_EXIDX section.
+## Also check that we are able to specify none of "Entries", "Content" nor "Size" keys.
+
+# RUN: yaml2obj --docnum=2 %s -o %t.props.o
+# RUN: llvm-readelf --sections %t.props.o | FileCheck %s --check-prefix=PROPERTIES
+
+# PROPERTIES: [Nr] Name       Type      Address          Off    Size   ES Flg Lk    Inf Al
+# PROPERTIES: [ 1] .ARM.exidx ARM_EXIDX 0000000000001122 000055 000000 00 AMS 13124 0   85
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_ARM
+Sections:
+  - Name:         .ARM.exidx
+    Type:         SHT_ARM_EXIDX
+    Flags:        [ SHF_ALLOC, SHF_MERGE, SHF_STRINGS ]
+    Address:      0x1122
+    Link:         0x3344
+    AddressAlign: 0x55
+    EntSize:      0x66
+
+## Check we can't use "Entries" key together with "Content" or "Size" keys.
+
+# RUN: not yaml2obj --docnum=3 -DSIZE=0 -DENT="[]" %s 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=ENTRIES-ERR
+# RUN: not yaml2obj --docnum=3 -DCONTENT="'00'" -DENT="[]" %s 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=ENTRIES-ERR
+
+# ENTRIES-ERR: error: "Entries" cannot be used with "Content" or "Size"
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_ARM
+Sections:
+  - Name:    .ARM.exidx
+    Type:    SHT_ARM_EXIDX
+    Size:    [[SIZE=<none>]]
+    Content: [[CONTENT=<none>]]
+    Entries: [[ENT=<none>]]
+
+## Check we can use "Content" key with "Size" key when the size is greater
+## than or equal to the content size.
+
+# RUN: not yaml2obj --docnum=3 -DCONTENT="'00'" -DSIZE=0 %s 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=CONTENT-SIZE-ERR
+
+# CONTENT-SIZE-ERR: error: "Size" must be greater than or equal to the content size
+
+# RUN: yaml2obj --docnum=3 -DCONTENT="'00'" -DSIZE=1 %s -o %t.cont.size.eq.o
+# RUN: llvm-readobj --sections --section-data %t.cont.size.eq.o | \
+# RUN:   FileCheck %s --check-prefix=CHECK-CONTENT -DDATA="00"
+
+# RUN: yaml2obj --docnum=3 -DCONTENT="'00'" -DSIZE=2 %s -o %t.cont.size.gr.o
+# RUN: llvm-readobj --sections --section-data %t.cont.size.gr.o | \
+# RUN:   FileCheck %s --check-prefix=CHECK-CONTENT -DDATA="0000"
+
+# CHECK-CONTENT:      Name: .ARM.exidx
+# CHECK-CONTENT:      SectionData (
+# CHECK-CONTENT-NEXT:   0000: [[DATA]] |
+# CHECK-CONTENT-NEXT: )
+
+## Check we can use "Content" key alone to emit arbitrary content.
+
+# RUN: yaml2obj --docnum=3 -DCONTENT="'11223344'" %s -o %t.content.o
+# RUN: llvm-readobj --sections --section-data %t.content.o | \
+# RUN:   FileCheck %s --check-prefix=CHECK-CONTENT -DDATA="11223344"
+
+## Check we can use "Size" key alone to emit content of an arbitrary size.
+
+# RUN: yaml2obj --docnum=3 -DSIZE=4 %s -o %t.size.o
+# RUN: llvm-readobj --sections --section-data %t.size.o | \
+# RUN:   FileCheck %s --check-prefix=CHECK-CONTENT -DDATA="00000000"

diff  --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp
index c70a49363aa9..a8eae03c0b78 100644
--- a/llvm/tools/obj2yaml/elf2yaml.cpp
+++ b/llvm/tools/obj2yaml/elf2yaml.cpp
@@ -95,6 +95,8 @@ class ELFDumper {
   Expected<ELFYAML::SymverSection *> dumpSymverSection(const Elf_Shdr *Shdr);
   Expected<ELFYAML::VerneedSection *> dumpVerneedSection(const Elf_Shdr *Shdr);
   Expected<ELFYAML::Group *> dumpGroup(const Elf_Shdr *Shdr);
+  Expected<ELFYAML::ARMIndexTableSection *>
+  dumpARMIndexTableSection(const Elf_Shdr *Shdr);
   Expected<ELFYAML::MipsABIFlags *> dumpMipsABIFlags(const Elf_Shdr *Shdr);
   Expected<ELFYAML::StackSizesSection *>
   dumpStackSizesSection(const Elf_Shdr *Shdr);
@@ -460,6 +462,9 @@ ELFDumper<ELFT>::dumpSections() {
 
   auto GetDumper = [this](unsigned Type)
       -> std::function<Expected<ELFYAML::Chunk *>(const Elf_Shdr *)> {
+    if (Obj.getHeader().e_machine == ELF::EM_ARM && Type == ELF::SHT_ARM_EXIDX)
+      return [this](const Elf_Shdr *S) { return dumpARMIndexTableSection(S); };
+
     if (Obj.getHeader().e_machine == ELF::EM_MIPS &&
         Type == ELF::SHT_MIPS_ABIFLAGS)
       return [this](const Elf_Shdr *S) { return dumpMipsABIFlags(S); };
@@ -1348,6 +1353,33 @@ Expected<ELFYAML::Group *> ELFDumper<ELFT>::dumpGroup(const Elf_Shdr *Shdr) {
   return S.release();
 }
 
+template <class ELFT>
+Expected<ELFYAML::ARMIndexTableSection *>
+ELFDumper<ELFT>::dumpARMIndexTableSection(const Elf_Shdr *Shdr) {
+  auto S = std::make_unique<ELFYAML::ARMIndexTableSection>();
+  if (Error E = dumpCommonSection(Shdr, *S))
+    return std::move(E);
+
+  Expected<ArrayRef<uint8_t>> ContentOrErr = Obj.getSectionContents(*Shdr);
+  if (!ContentOrErr)
+    return ContentOrErr.takeError();
+
+  if (ContentOrErr->size() % (sizeof(Elf_Word) * 2) != 0) {
+    S->Content = yaml::BinaryRef(*ContentOrErr);
+    return S.release();
+  }
+
+  ArrayRef<Elf_Word> Words(
+      reinterpret_cast<const Elf_Word *>(ContentOrErr->data()),
+      ContentOrErr->size() / sizeof(Elf_Word));
+
+  S->Entries.emplace();
+  for (size_t I = 0, E = Words.size(); I != E; I += 2)
+    S->Entries->push_back({(yaml::Hex32)Words[I], (yaml::Hex32)Words[I + 1]});
+
+  return S.release();
+}
+
 template <class ELFT>
 Expected<ELFYAML::MipsABIFlags *>
 ELFDumper<ELFT>::dumpMipsABIFlags(const Elf_Shdr *Shdr) {


        


More information about the llvm-commits mailing list