[llvm] 18cf93a - [llvm-readobj][llvm-readelf] - Refactor parsing of the SHT_GNU_versym section.

Georgii Rymar via llvm-commits llvm-commits at lists.llvm.org
Fri Dec 6 04:36:06 PST 2019


Author: Georgii Rymar
Date: 2019-12-06T15:35:05+03:00
New Revision: 18cf93a6eddfd201df87f9152bee38e81dfdc40f

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

LOG: [llvm-readobj][llvm-readelf] - Refactor parsing of the SHT_GNU_versym section.

This introduce a new helper which is used to parse the SHT_GNU_versym section.
LLVM/GNU styles implementations now use it to share the logic.

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

Added: 
    llvm/test/tools/llvm-readobj/elf-versym-invalid.test

Modified: 
    llvm/test/Object/invalid.test
    llvm/test/Object/multiple-sections.yaml
    llvm/test/tools/llvm-readobj/all.test
    llvm/test/tools/llvm-readobj/elf-verdef-invalid.test
    llvm/test/tools/llvm-readobj/elf-verneed-invalid.test
    llvm/tools/llvm-readobj/ELFDumper.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/test/Object/invalid.test b/llvm/test/Object/invalid.test
index 37563652bd63..91a93b06b967 100644
--- a/llvm/test/Object/invalid.test
+++ b/llvm/test/Object/invalid.test
@@ -637,13 +637,13 @@ Sections:
 Symbols:
   - Name: foo
 
-## Check that we report an error if SHT_GNU_versym has invalid
+## Check that we report a warning if SHT_GNU_versym has invalid
 ## sh_entsize value (3 instead of 2) when trying to access the entries.
 
 # RUN: yaml2obj %s --docnum=30 -o %t30
-# RUN: not llvm-readobj -V %t30 2>&1 | FileCheck -DFILE=%t30 --check-prefix=INVALID-VER-SHENTSIZE %s
+# RUN: llvm-readobj -V %t30 2>&1 | FileCheck -DFILE=%t30 --check-prefix=INVALID-VER-SHENTSIZE %s
 
-# INVALID-VER-SHENTSIZE: error: '[[FILE]]': section [index 1] has invalid sh_entsize: expected 2, but got 3
+# INVALID-VER-SHENTSIZE: warning: '[[FILE]]': cannot read content of SHT_GNU_versym section with index 1: section [index 1] has an invalid sh_entsize: 3
 
 --- !ELF
 FileHeader:
@@ -657,6 +657,7 @@ Sections:
     Type:    SHT_GNU_versym
     EntSize: 0x0000000000000003
     Entries: [ ]
+    Link:    .dynsym
 ## Needed to trigger creation of .dynsym.
 DynamicSymbols:
   - Name:    foo

diff  --git a/llvm/test/Object/multiple-sections.yaml b/llvm/test/Object/multiple-sections.yaml
index 197725595be0..55b0ce84409d 100644
--- a/llvm/test/Object/multiple-sections.yaml
+++ b/llvm/test/Object/multiple-sections.yaml
@@ -4,6 +4,7 @@
 # Test that multiple sections with the same type does not trigger an error.
 
 # CHECK: ElfHeader {
+# CHECK: VersionSymbols [
 # CHECK: VersionDefinitions [
 # CHECK: VersionRequirements [
 # CHECK: CGProfile [
@@ -23,10 +24,12 @@ Sections:
     EntSize:         24
   - Name:            .versym
     Type:            SHT_GNU_versym
-    Entries:         [ ]
+    Entries:         [ 0 ]
+    Link:            .dynsym
   - Name:            .versym2
     Type:            SHT_GNU_versym
-    Entries:         [ ]
+    Entries:         [ 0 ]
+    Link:            .dynsym
   - Name:            .verdef
     Type:            SHT_GNU_verdef
     Info:            0x0000000000000000
@@ -59,4 +62,5 @@ Sections:
     Content:         ''
 Symbols:         
   - Name:            f
+DynamicSymbols: []
 ...

diff  --git a/llvm/test/tools/llvm-readobj/all.test b/llvm/test/tools/llvm-readobj/all.test
index 5edda0af1f9c..1f617034d0e4 100644
--- a/llvm/test/tools/llvm-readobj/all.test
+++ b/llvm/test/tools/llvm-readobj/all.test
@@ -53,6 +53,7 @@ Sections:
   - Name:    .gnu.version
     Type:    SHT_GNU_versym
     Entries: [ 0 ]
+    Link:    .dynsym
   - Name:    .gnu.version_d
     Type:    SHT_GNU_verdef
     Info:    0x0
@@ -111,3 +112,4 @@ ProgramHeaders:
     Sections:
       - Section: .note.gnu.build-id
 Symbols: []
+DynamicSymbols: []

diff  --git a/llvm/test/tools/llvm-readobj/elf-verdef-invalid.test b/llvm/test/tools/llvm-readobj/elf-verdef-invalid.test
index 2eb262f555c1..f80e9383f708 100644
--- a/llvm/test/tools/llvm-readobj/elf-verdef-invalid.test
+++ b/llvm/test/tools/llvm-readobj/elf-verdef-invalid.test
@@ -275,6 +275,7 @@ DynamicSymbols:
 # INVALID-VERDEF-LLVM-NEXT:      Name:
 # INVALID-VERDEF-LLVM-NEXT:    }
 # INVALID-VERDEF-LLVM-NEXT:    Symbol {
+# INVALID-VERDEF-LLVM-NEXT:    Version: 2
 # INVALID-VERDEF-LLVM-EMPTY:
 # INVALID-VERDEF-LLVM-NEXT:  error: '[[FILE]]': invalid SHT_GNU_verdef section with index 2: version definition 1 goes past the end of the section
 

diff  --git a/llvm/test/tools/llvm-readobj/elf-verneed-invalid.test b/llvm/test/tools/llvm-readobj/elf-verneed-invalid.test
index 6a04519a05d6..e8d75afe1e6a 100644
--- a/llvm/test/tools/llvm-readobj/elf-verneed-invalid.test
+++ b/llvm/test/tools/llvm-readobj/elf-verneed-invalid.test
@@ -101,9 +101,9 @@ DynamicSymbols:
 # LLVM-NOLINK-NEXT:     Name:
 # LLVM-NOLINK-NEXT:   }
 # LLVM-NOLINK-NEXT:   Symbol {
+# LLVM-NOLINK-NEXT:     Version: 2
 # LLVM-NOLINK-EMPTY:
 # LLVM-NOLINK-NEXT:  warning: '[[FILE]]': invalid string table linked to SHT_GNU_verneed section with index 2: invalid sh_type for string table section [index 0]: expected SHT_STRTAB, but got SHT_NULL
-# LLVM-NOLINK-NEXT:     Version: 2
 # LLVM-NOLINK-NEXT:     Name: foo@<corrupt>
 # LLVM-NOLINK-NEXT:   }
 # LLVM-NOLINK-NEXT: ]
@@ -183,8 +183,7 @@ Sections:
     AddressAlign: 4
 ## The byte offset to the auxiliary entry is 0x11, i.e. it is not correctly aligned in memory.
     Content: "0100010001000000110000000000000000000000"
-DynamicSymbols:
-  - Name: foo
+DynamicSymbols: []
 
 ## Here we check that we can properly dump the case when a dependency file name
 ## and/or a dependency name string offset is equal to the string table size.

diff  --git a/llvm/test/tools/llvm-readobj/elf-versym-invalid.test b/llvm/test/tools/llvm-readobj/elf-versym-invalid.test
new file mode 100644
index 000000000000..a88318e5f492
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/elf-versym-invalid.test
@@ -0,0 +1,220 @@
+## Test how llvm-readobj/llvm-readelf tools handle invalid SHT_GNU_versym sections.
+
+## Check that we report a warning when sh_link references a non-existent section.
+
+# RUN: yaml2obj --docnum=1 %s -o %t1
+# RUN: llvm-readelf -V %t1 2>&1 | FileCheck -DFILE=%t1 %s --check-prefix=GNU-INVALID-LINK
+# RUN: llvm-readobj -V %t1 2>&1 | FileCheck -DFILE=%t1 %s --check-prefix=LLVM-INVALID-LINK
+
+# GNU-INVALID-LINK:       Version symbols section '.gnu.version' contains 0 entries:
+# GNU-INVALID-LINK-EMPTY:
+# GNU-INVALID-LINK-NEXT:  warning: '[[FILE]]': invalid section linked to SHT_GNU_versym section with index 1: invalid section index: 255
+# GNU-INVALID-LINK-NEXT:   Addr: 0000000000000000  Offset: 0x000040  Link: 255 (<corrupt>)
+
+# LLVM-INVALID-LINK:       VersionSymbols [
+# LLVM-INVALID-LINK-EMPTY:
+# LLVM-INVALID-LINK-NEXT:  warning: '[[FILE]]': invalid section linked to SHT_GNU_versym section with index 1: invalid section index: 255
+# LLVM-INVALID-LINK-NEXT:  ]
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Name:    .gnu.version
+    Type:    SHT_GNU_versym
+    Link:    0xFF
+    Entries: [ ]
+
+## Check that we report a warning when the sh_link field of a SHT_GNU_versym section does not reference
+## a dynamic symbol table section.
+
+# RUN: yaml2obj --docnum=2 %s -o %t2
+# RUN: llvm-readelf -V %t2 2>&1 | FileCheck -DFILE=%t2 %s --check-prefix=INVALID-SYMBOL-TABLE-GNU
+# RUN: llvm-readobj -V %t2 2>&1 | FileCheck -DFILE=%t2 %s --check-prefix=INVALID-SYMBOL-TABLE-LLVM
+
+# INVALID-SYMBOL-TABLE-GNU:       Version symbols section '.gnu.version' contains 1 entries:
+# INVALID-SYMBOL-TABLE-GNU-NEXT:   Addr: 0000000000000000  Offset: 0x000040  Link: 0 ()
+# INVALID-SYMBOL-TABLE-GNU-EMPTY:
+# INVALID-SYMBOL-TABLE-GNU-NEXT:   warning: '[[FILE]]': invalid section linked to SHT_GNU_versym section with index 1: expected SHT_DYNSYM, but got SHT_NULL
+# INVALID-SYMBOL-TABLE-GNU-NEXT:   000:   0 (*local*)
+
+# INVALID-SYMBOL-TABLE-LLVM:       VersionSymbols [
+# INVALID-SYMBOL-TABLE-LLVM-EMPTY:
+# INVALID-SYMBOL-TABLE-LLVM-NEXT:  warning: '[[FILE]]': invalid section linked to SHT_GNU_versym section with index 1: expected SHT_DYNSYM, but got SHT_NULL
+# INVALID-SYMBOL-TABLE-LLVM-NEXT:  ]
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Name:    .gnu.version
+    Type:    SHT_GNU_versym
+    Link:    0x0
+    Entries: [ 0 ]
+
+## Check we report a warning when something is wrong with a string table linked to a symbol table that
+## is linked with SHT_GNU_versym. In this case we are unable to produce LLVM style output,
+## but GNU style is fine because it does not need that string table.
+
+# RUN: yaml2obj --docnum=3 %s -o %t3
+# RUN: llvm-readelf -V %t3 2>&1 | FileCheck -DFILE=%t3 %s --check-prefix=INVALID-STRING-TABLE-GNU
+# RUN: llvm-readobj -V %t3 2>&1 | FileCheck -DFILE=%t3 %s --check-prefix=INVALID-STRING-TABLE-LLVM
+
+# INVALID-STRING-TABLE-GNU:       Version symbols section '.gnu.version' contains 1 entries:
+# INVALID-STRING-TABLE-GNU-NEXT:   Addr: 0000000000000000  Offset: 0x000040  Link: 5 (.dynsym)
+# INVALID-STRING-TABLE-GNU-EMPTY:
+# INVALID-STRING-TABLE-GNU-NEXT:   warning: '[[FILE]]': can't get a string table for the symbol table linked to SHT_GNU_versym section with index 1: invalid string table linked to SHT_DYNSYM section with index 5: invalid sh_type for string table section [index 2]: expected SHT_STRTAB, but got SHT_NULL
+# INVALID-STRING-TABLE-GNU-NEXT:   000:   0 (*local*)
+
+# INVALID-STRING-TABLE-LLVM:       VersionSymbols [
+# INVALID-STRING-TABLE-LLVM-EMPTY:
+# INVALID-STRING-TABLE-LLVM-NEXT:  warning: '[[FILE]]': can't get a string table for the symbol table linked to SHT_GNU_versym section with index 1: invalid string table linked to SHT_DYNSYM section with index 5: invalid sh_type for string table section [index 2]: expected SHT_STRTAB, but got SHT_NULL
+# INVALID-STRING-TABLE-LLVM-NEXT:  ]
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Name:    .gnu.version
+    Type:    SHT_GNU_versym
+    Link:    .dynsym
+    Entries: [ 0 ]
+  - Name:    .dynstr
+    Type:    SHT_NULL
+DynamicSymbols: []
+
+## Check we report a warning when a SHT_GNU_versym section is not correctly aligned in memory.
+
+# RUN: yaml2obj --docnum=4 %s -o %t4
+# RUN: llvm-readelf -V %t4 2>&1 | FileCheck -DFILE=%t4 %s --check-prefix=MISALIGNED-GNU
+# RUN: llvm-readobj -V %t4 2>&1 | FileCheck -DFILE=%t4 %s --check-prefix=MISALIGNED-LLVM
+
+# MISALIGNED-GNU:       Version symbols section '.gnu.version' contains 0 entries:
+# MISALIGNED-GNU-NEXT:   Addr: 0000000000000000  Offset: 0x00ffff  Link: 0 ()
+# MISALIGNED-GNU-EMPTY:
+# MISALIGNED-GNU-NEXT:   warning: '[[FILE]]': the SHT_GNU_versym section with index 1 is misaligned
+
+# MISALIGNED-LLVM:       VersionSymbols [
+# MISALIGNED-LLVM-EMPTY:
+# MISALIGNED-LLVM-NEXT:   warning: '[[FILE]]': the SHT_GNU_versym section with index 1 is misaligned
+# MISALIGNED-LLVM-NEXT:  ]
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Name:    .gnu.version
+    Type:    SHT_GNU_versym
+    Entries: [ ]
+    ShOffset: 0xffff
+
+## Check we report a warning when a SHT_GNU_versym section has an invalid entry size.
+
+# RUN: yaml2obj --docnum=5 %s -o %t5
+# RUN: llvm-readelf -V %t5 2>&1 | FileCheck -DFILE=%t5 %s --check-prefix=INVALID-ENT-SIZE-GNU
+# RUN: llvm-readobj -V %t5 2>&1 | FileCheck -DFILE=%t5 %s --check-prefix=INVALID-ENT-SIZE-LLVM
+
+# INVALID-ENT-SIZE-GNU:       Version symbols section '.gnu.version' contains 1 entries:
+# INVALID-ENT-SIZE-GNU-NEXT:   Addr: 0000000000000000  Offset: 0x000040  Link: 0 ()
+# INVALID-ENT-SIZE-GNU-EMPTY:
+# INVALID-ENT-SIZE-GNU-NEXT:  warning: '[[FILE]]': cannot read content of SHT_GNU_versym section with index 1: section [index 1] has an invalid sh_entsize: 3
+
+# INVALID-ENT-SIZE-LLVM:       VersionSymbols [
+# INVALID-ENT-SIZE-LLVM-EMPTY:
+# INVALID-ENT-SIZE-LLVM-NEXT:  warning: '[[FILE]]': cannot read content of SHT_GNU_versym section with index 1: section [index 1] has an invalid sh_entsize: 3
+# INVALID-ENT-SIZE-LLVM-NEXT:  ]
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Name:    .gnu.version
+    Type:    SHT_GNU_versym
+    Entries: [ 0 ]
+    EntSize: 3
+
+## Check we report a warning when the number of version entries does not match the number of symbols in the associated symbol table.
+
+# RUN: yaml2obj --docnum=6 %s -o %t6
+# RUN: llvm-readelf -V %t6 2>&1 | FileCheck -DFILE=%t6 %s --check-prefix=SYMBOLS-NUM-MISMATCH-GNU
+# RUN: llvm-readobj -V %t6 2>&1 | FileCheck -DFILE=%t6 %s --check-prefix=SYMBOLS-NUM-MISMATCH-LLVM
+
+# SYMBOLS-NUM-MISMATCH-GNU:       Version symbols section '.gnu.version' contains 2 entries:
+# SYMBOLS-NUM-MISMATCH-GNU-NEXT:   Addr: 0000000000000000  Offset: 0x000040  Link: 4 (.dynsym)
+# SYMBOLS-NUM-MISMATCH-GNU-EMPTY:
+# SYMBOLS-NUM-MISMATCH-GNU-NEXT:   warning: '[[FILE]]': SHT_GNU_versym section with index 1: the number of entries (2) does not match the number of symbols (3) in the symbol table with index 4
+# SYMBOLS-NUM-MISMATCH-GNU-NEXT:    000:   0 (*local*)       1 (*global*)
+
+# SYMBOLS-NUM-MISMATCH-LLVM:       VersionSymbols [
+# SYMBOLS-NUM-MISMATCH-LLVM-EMPTY:
+# SYMBOLS-NUM-MISMATCH-LLVM-NEXT:  warning: '[[FILE]]': SHT_GNU_versym section with index 1: the number of entries (2) does not match the number of symbols (3) in the symbol table with index 4
+# SYMBOLS-NUM-MISMATCH-LLVM-NEXT:  ]
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Name:    .gnu.version
+    Type:    SHT_GNU_versym
+    Entries: [ 0, 1 ]
+    Link:   .dynsym
+DynamicSymbols:
+  - Name: foo
+  - Name: bar
+
+## Check we can dump a SHT_GNU_versym section when it is linked to a custom dynamic symbol
+## table that is not called ".dynsym".
+
+# RUN: yaml2obj --docnum=7 %s -o %t7
+# RUN: llvm-readelf -V %t7 2>&1 | FileCheck -DFILE=%t7 %s --check-prefix=CUSTOM-SYMTAB-GNU
+# RUN: llvm-readobj -V %t7 2>&1 | FileCheck -DFILE=%t7 %s --check-prefix=CUSTOM-SYMTAB-LLVM
+
+# CUSTOM-SYMTAB-GNU:      Version symbols section '.gnu.version' contains 1 entries:
+# CUSTOM-SYMTAB-GNU-NEXT:   Addr: 0000000000000000  Offset: 0x000040  Link: 2 (.foo.dynsym)
+# CUSTOM-SYMTAB-GNU-NEXT:    000:   0 (*local*)
+
+# CUSTOM-SYMTAB-LLVM:      VersionSymbols [
+# CUSTOM-SYMTAB-LLVM-NEXT:  Symbol {
+# CUSTOM-SYMTAB-LLVM-NEXT:    Version: 0
+# CUSTOM-SYMTAB-LLVM-NEXT:    Name:
+# CUSTOM-SYMTAB-LLVM-NEXT:  }
+# CUSTOM-SYMTAB-LLVM-NEXT: ]
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Name:    .gnu.version
+    Type:    SHT_GNU_versym
+    Link:    .foo.dynsym
+    Entries: [ 0 ]
+## A custom empty dynamic symbol table with a null entry.
+  - Name:    .foo.dynsym
+    Type:    SHT_DYNSYM
+    Link:    .dynstr
+    EntSize: 24
+    Size:    24
+DynamicSymbols:
+  - Name: foo
+  - Name: bar

diff  --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 69b954063865..1bb2c505af6f 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -339,6 +339,9 @@ template <typename ELFT> class ELFDumper : public ObjDumper {
   const Elf_Hash *getHashTable() const { return HashTable; }
   const Elf_GnuHash *getGnuHashTable() const { return GnuHashTable; }
 
+  Expected<ArrayRef<Elf_Versym>> getVersionTable(const Elf_Shdr *Sec,
+                                                 ArrayRef<Elf_Sym> *SymTab,
+                                                 StringRef *StrTab) const;
   Expected<std::vector<VerDef>>
   getVersionDefinitions(const Elf_Shdr *Sec) const;
   Expected<std::vector<VerNeed>>
@@ -368,6 +371,90 @@ static Expected<StringRef> getLinkAsStrtab(const ELFFile<ELFT> *Obj,
   return *StrTabOrErr;
 }
 
+// Returns the linked symbol table and associated string table for a given section.
+template <class ELFT>
+static Expected<std::pair<typename ELFT::SymRange, StringRef>>
+getLinkAsSymtab(const ELFFile<ELFT> *Obj, const typename ELFT::Shdr *Sec,
+                   unsigned SecNdx, unsigned ExpectedType) {
+  Expected<const typename ELFT::Shdr *> SymtabOrErr =
+      Obj->getSection(Sec->sh_link);
+  if (!SymtabOrErr)
+    return createError("invalid section linked to " +
+                       object::getELFSectionTypeName(
+                           Obj->getHeader()->e_machine, Sec->sh_type) +
+                       " section with index " + Twine(SecNdx) + ": " +
+                       toString(SymtabOrErr.takeError()));
+
+  if ((*SymtabOrErr)->sh_type != ExpectedType)
+    return createError(
+        "invalid section linked to " +
+        object::getELFSectionTypeName(Obj->getHeader()->e_machine,
+                                      Sec->sh_type) +
+        " section with index " + Twine(SecNdx) + ": expected " +
+        object::getELFSectionTypeName(Obj->getHeader()->e_machine,
+                                      ExpectedType) +
+        ", but got " +
+        object::getELFSectionTypeName(Obj->getHeader()->e_machine,
+                                      (*SymtabOrErr)->sh_type));
+
+  Expected<StringRef> StrTabOrErr =
+      getLinkAsStrtab(Obj, *SymtabOrErr, Sec->sh_link);
+  if (!StrTabOrErr)
+    return createError(
+        "can't get a string table for the symbol table linked to " +
+        object::getELFSectionTypeName(Obj->getHeader()->e_machine,
+                                      Sec->sh_type) +
+        " section with index " + Twine(SecNdx) + ": " +
+        toString(StrTabOrErr.takeError()));
+
+  Expected<typename ELFT::SymRange> SymsOrErr = Obj->symbols(*SymtabOrErr);
+  if (!SymsOrErr)
+    return createError(
+        "unable to read symbols from the symbol table with index " +
+        Twine(Sec->sh_link) + ": " + toString(SymsOrErr.takeError()));
+
+  return std::make_pair(*SymsOrErr, *StrTabOrErr);
+}
+
+template <class ELFT>
+Expected<ArrayRef<typename ELFT::Versym>>
+ELFDumper<ELFT>::getVersionTable(const Elf_Shdr *Sec, ArrayRef<Elf_Sym> *SymTab,
+                                 StringRef *StrTab) const {
+  assert((!SymTab && !StrTab) || (SymTab && StrTab));
+  const ELFFile<ELFT> *Obj = ObjF->getELFFile();
+  unsigned SecNdx = Sec - &cantFail(Obj->sections()).front();
+
+  if (uintptr_t(Obj->base() + Sec->sh_offset) % sizeof(uint16_t) != 0)
+    return createError("the SHT_GNU_versym section with index " +
+                       Twine(SecNdx) + " is misaligned");
+
+  Expected<ArrayRef<Elf_Versym>> VersionsOrErr =
+      Obj->template getSectionContentsAsArray<Elf_Versym>(Sec);
+  if (!VersionsOrErr)
+    return createError(
+        "cannot read content of SHT_GNU_versym section with index " +
+        Twine(SecNdx) + ": " + toString(VersionsOrErr.takeError()));
+
+  Expected<std::pair<ArrayRef<Elf_Sym>, StringRef>> SymTabOrErr =
+      getLinkAsSymtab(Obj, Sec, SecNdx, SHT_DYNSYM);
+  if (!SymTabOrErr) {
+    ELFDumperStyle->reportUniqueWarning(SymTabOrErr.takeError());
+    return *VersionsOrErr;
+  }
+
+  if (SymTabOrErr->first.size() != VersionsOrErr->size())
+    ELFDumperStyle->reportUniqueWarning(
+        createError("SHT_GNU_versym section with index " + Twine(SecNdx) +
+                    ": the number of entries (" + Twine(VersionsOrErr->size()) +
+                    ") does not match the number of symbols (" +
+                    Twine(SymTabOrErr->first.size()) +
+                    ") in the symbol table with index " + Twine(Sec->sh_link)));
+
+  if (SymTab)
+    std::tie(*SymTab, *StrTab) = *SymTabOrErr;
+  return *VersionsOrErr;
+}
+
 template <class ELFT>
 Expected<std::vector<VerDef>>
 ELFDumper<ELFT>::getVersionDefinitions(const Elf_Shdr *Sec) const {
@@ -4013,23 +4100,24 @@ void GNUStyle<ELFT>::printVersionSymbolSection(const ELFFile<ELFT> *Obj,
   if (!Sec)
     return;
 
-  unsigned Entries = Sec->sh_size / sizeof(Elf_Versym);
-  printGNUVersionSectionProlog(Obj, Sec, "Version symbols", Entries);
-
-  const uint8_t *VersymBuf =
-      reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset);
-  const ELFDumper<ELFT> *Dumper = this->dumper();
+  printGNUVersionSectionProlog(Obj, Sec, "Version symbols",
+                               Sec->sh_size / sizeof(Elf_Versym));
+  Expected<ArrayRef<Elf_Versym>> VerTableOrErr =
+      this->dumper()->getVersionTable(Sec, /*SymTab=*/nullptr,
+                                      /*StrTab=*/nullptr);
+  if (!VerTableOrErr) {
+    this->reportUniqueWarning(VerTableOrErr.takeError());
+    return;
+  }
 
   // readelf prints 4 entries per line.
+  uint64_t Entries = VerTableOrErr->size();
   for (uint64_t VersymRow = 0; VersymRow < Entries; VersymRow += 4) {
     OS << "  " << format_hex_no_prefix(VersymRow, 3) << ":";
 
-    for (uint64_t VersymIndex = 0;
-         (VersymIndex < 4) && (VersymIndex + VersymRow) < Entries;
-         ++VersymIndex) {
-      const Elf_Versym *Versym =
-          reinterpret_cast<const Elf_Versym *>(VersymBuf);
-      switch (Versym->vs_index) {
+    for (uint64_t I = 0; (I < 4) && (I + VersymRow) < Entries; ++I) {
+      unsigned Version = (*VerTableOrErr)[VersymRow + I].vs_index;
+      switch (Version) {
       case 0:
         OS << "   0 (*local*)    ";
         break;
@@ -4039,18 +4127,17 @@ void GNUStyle<ELFT>::printVersionSymbolSection(const ELFFile<ELFT> *Obj,
       default:
         bool IsDefault = true;
         std::string VersionName =
-            Dumper->getSymbolVersionByIndex(Versym->vs_index, IsDefault);
+            this->dumper()->getSymbolVersionByIndex(Version, IsDefault);
 
         if (!VersionName.empty())
           VersionName = "(" + VersionName + ")";
         else
           VersionName = "(*invalid*)";
 
-        OS << format("%4x%c", Versym->vs_index & VERSYM_VERSION,
-                     Versym->vs_index & VERSYM_HIDDEN ? 'h' : ' ');
+        OS << format("%4x%c", Version & VERSYM_VERSION,
+                     Version & VERSYM_HIDDEN ? 'h' : ' ');
         OS << left_justify(VersionName, 13);
       }
-      VersymBuf += sizeof(Elf_Versym);
     }
     OS << '\n';
   }
@@ -5834,20 +5921,23 @@ void LLVMStyle<ELFT>::printVersionSymbolSection(const ELFFile<ELFT> *Obj,
   if (!Sec)
     return;
 
-  const uint8_t *VersymBuf =
-      reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset);
-  const ELFDumper<ELFT> *Dumper = this->dumper();
-  StringRef StrTable = Dumper->getDynamicStringTable();
+  StringRef StrTable;
+  ArrayRef<Elf_Sym> Syms;
+  Expected<ArrayRef<Elf_Versym>> VerTableOrErr =
+      this->dumper()->getVersionTable(Sec, &Syms, &StrTable);
+  if (!VerTableOrErr) {
+    this->reportUniqueWarning(VerTableOrErr.takeError());
+    return;
+  }
+
+  if (StrTable.empty() || Syms.empty() || Syms.size() != VerTableOrErr->size())
+    return;
 
-  // Same number of entries in the dynamic symbol table (DT_SYMTAB).
-  for (const Elf_Sym &Sym : Dumper->dynamic_symbols()) {
+  for (size_t I = 0, E = Syms.size(); I < E; ++I) {
     DictScope S(W, "Symbol");
-    const Elf_Versym *Versym = reinterpret_cast<const Elf_Versym *>(VersymBuf);
-    std::string FullSymbolName =
-        Dumper->getFullSymbolName(&Sym, StrTable, true /* IsDynamic */);
-    W.printNumber("Version", Versym->vs_index & VERSYM_VERSION);
-    W.printString("Name", FullSymbolName);
-    VersymBuf += sizeof(Elf_Versym);
+    W.printNumber("Version", (*VerTableOrErr)[I].vs_index & VERSYM_VERSION);
+    W.printString("Name", this->dumper()->getFullSymbolName(
+                              &Syms[I], StrTable, /*IsDynamic=*/true));
   }
 }
 


        


More information about the llvm-commits mailing list