[llvm] c653a52 - [llvm-readobj/llvm-readelf] - Reimplement dumping of the SHT_GNU_verneed section.

Georgii Rymar via llvm-commits llvm-commits at lists.llvm.org
Mon Dec 2 01:27:54 PST 2019


Author: Georgii Rymar
Date: 2019-12-02T12:27:31+03:00
New Revision: c653a52c85ff913bcbef007082763dbc754d6933

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

LOG: [llvm-readobj/llvm-readelf] - Reimplement dumping of the SHT_GNU_verneed section.

This is similar to D70495, but for SHT_GNU_verneed section.
It solves the same problems: different implementations, lack of error reporting
and no test coverage.

DIfferential revision: https://reviews.llvm.org/D70826

Added: 
    

Modified: 
    llvm/test/tools/llvm-readobj/elf-verneed-invalid.test
    llvm/tools/llvm-readobj/ELFDumper.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/test/tools/llvm-readobj/elf-verneed-invalid.test b/llvm/test/tools/llvm-readobj/elf-verneed-invalid.test
index 971cada0195a..53f8562989d5 100644
--- a/llvm/test/tools/llvm-readobj/elf-verneed-invalid.test
+++ b/llvm/test/tools/llvm-readobj/elf-verneed-invalid.test
@@ -81,16 +81,18 @@ DynamicSymbols:
 ## this situation properly.
 
 # RUN: yaml2obj --docnum=2 %s -o %t2
-# RUN: llvm-readelf -V %t2 | FileCheck %s --check-prefix=GNU-NOLINK
-# RUN: llvm-readobj -V %t2 | FileCheck %s --check-prefix=LLVM-NOLINK
+# RUN: llvm-readelf -V %t2 2>&1 | FileCheck %s -DFILE=%t2 --check-prefix=GNU-NOLINK
+# RUN: llvm-readobj -V %t2 2>&1 | FileCheck %s -DFILE=%t2 --check-prefix=LLVM-NOLINK
 
 # GNU-NOLINK:      Version symbols section '.gnu.version' contains 2 entries:
 # GNU-NOLINK-NEXT:  Addr: 0000000000000000  Offset: 0x000040  Link: 5 (.dynsym)
 # GNU-NOLINK-NEXT:   000:   0 (*local*)       2 (bar)
 # GNU-NOLINK:      Version needs section '.gnu.version_r' contains 1 entries:
 # GNU-NOLINK-NEXT:  Addr: 0000000000000000  Offset: 0x000044  Link: 0 ()
-# GNU-NOLINK-NEXT:   0x0000: Version: 1  File: <invalid>  Cnt: 1
-# GNU-NOLINK-NEXT:   0x0010:   Name: <invalid>  Flags: none Version: 2
+# GNU-NOLINK-EMPTY:
+# GNU-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
+# GNU-NOLINK-NEXT:   0x0000: Version: 1  File: <corrupt vn_file: 9>  Cnt: 1
+# GNU-NOLINK-NEXT:   0x0010:   Name: <corrupt>  Flags: none Version: 2
 
 # LLVM-NOLINK:      VersionSymbols [
 # LLVM-NOLINK:        Symbol {
@@ -104,17 +106,19 @@ DynamicSymbols:
 # LLVM-NOLINK-NEXT: ]
 
 # LLVM-NOLINK:      VersionRequirements [
+# 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:   Dependency {
 # LLVM-NOLINK-NEXT:     Version: 1
 # LLVM-NOLINK-NEXT:     Count: 1
-# LLVM-NOLINK-NEXT:     FileName: <invalid>
+# LLVM-NOLINK-NEXT:     FileName: <corrupt vn_file: 9>
 # LLVM-NOLINK-NEXT:     Entries [
 # LLVM-NOLINK-NEXT:       Entry {
 # LLVM-NOLINK-NEXT:         Hash: 0
 # LLVM-NOLINK-NEXT:         Flags [ (0x0)
 # LLVM-NOLINK-NEXT:         ]
 # LLVM-NOLINK-NEXT:         Index: 2
-# LLVM-NOLINK-NEXT:         Name: <invalid>
+# LLVM-NOLINK-NEXT:         Name: <corrupt>
 # LLVM-NOLINK-NEXT:       }
 # LLVM-NOLINK-NEXT:     ]
 # LLVM-NOLINK-NEXT:   }
@@ -212,14 +216,14 @@ DynamicSymbols:
 # LLVM-OFFSET-EQ-NEXT:   Dependency {
 # LLVM-OFFSET-EQ-NEXT:     Version: 1
 # LLVM-OFFSET-EQ-NEXT:     Count: 1
-# LLVM-OFFSET-EQ-NEXT:     FileName: <invalid>
+# LLVM-OFFSET-EQ-NEXT:     FileName: <corrupt vn_file: 1>
 # LLVM-OFFSET-EQ-NEXT:     Entries [
 # LLVM-OFFSET-EQ-NEXT:       Entry {
 # LLVM-OFFSET-EQ-NEXT:         Hash: 0
 # LLVM-OFFSET-EQ-NEXT:         Flags [ (0x0)
 # LLVM-OFFSET-EQ-NEXT:         ]
 # LLVM-OFFSET-EQ-NEXT:         Index: 0
-# LLVM-OFFSET-EQ-NEXT:         Name: <invalid>
+# LLVM-OFFSET-EQ-NEXT:         Name: <corrupt>
 # LLVM-OFFSET-EQ-NEXT:       }
 # LLVM-OFFSET-EQ-NEXT:     ]
 # LLVM-OFFSET-EQ-NEXT:   }
@@ -227,8 +231,8 @@ DynamicSymbols:
 
 # GNU-OFFSET-EQ:      Version needs section '.gnu.version_r' contains 1 entries:
 # GNU-OFFSET-EQ-NEXT:  Addr: 0000000000000000  Offset: 0x000044  Link: 1 (.mystrtab)
-# GNU-OFFSET-EQ-NEXT:   0x0000: Version: 1  File: <invalid>  Cnt: 1
-# GNU-OFFSET-EQ-NEXT:   0x0010:   Name: <invalid>  Flags: none  Version: 0
+# GNU-OFFSET-EQ-NEXT:   0x0000: Version: 1  File: <corrupt vn_file: 1>  Cnt: 1
+# GNU-OFFSET-EQ-NEXT:   0x0010:   Name: <corrupt>  Flags: none  Version: 0
 
 --- !ELF
 FileHeader:
@@ -268,14 +272,14 @@ DynamicSymbols:
 # LLVM-OFFSET-GR-NEXT:   Dependency {
 # LLVM-OFFSET-GR-NEXT:     Version: 1
 # LLVM-OFFSET-GR-NEXT:     Count: 1
-# LLVM-OFFSET-GR-NEXT:     FileName: <invalid>
+# LLVM-OFFSET-GR-NEXT:     FileName: <corrupt vn_file: 1>
 # LLVM-OFFSET-GR-NEXT:     Entries [
 # LLVM-OFFSET-GR-NEXT:       Entry {
 # LLVM-OFFSET-GR-NEXT:         Hash: 0
 # LLVM-OFFSET-GR-NEXT:         Flags [ (0x0)
 # LLVM-OFFSET-GR-NEXT:         ]
 # LLVM-OFFSET-GR-NEXT:         Index: 0
-# LLVM-OFFSET-GR-NEXT:         Name: <invalid>
+# LLVM-OFFSET-GR-NEXT:         Name: <corrupt>
 # LLVM-OFFSET-GR-NEXT:       }
 # LLVM-OFFSET-GR-NEXT:     ]
 # LLVM-OFFSET-GR-NEXT:   }
@@ -283,8 +287,8 @@ DynamicSymbols:
 
 # GNU-OFFSET-GR:      Version needs section '.gnu.version_r' contains 1 entries:
 # GNU-OFFSET-GR-NEXT:  Addr: 0000000000000000  Offset: 0x000040  Link: 1 (.mystrtab)
-# GNU-OFFSET-GR-NEXT:   0x0000: Version: 1  File: <invalid>  Cnt: 1
-# GNU-OFFSET-GR-NEXT:   0x0010:   Name: <invalid>  Flags: none  Version: 0
+# GNU-OFFSET-GR-NEXT:   0x0000: Version: 1  File: <corrupt vn_file: 1>  Cnt: 1
+# GNU-OFFSET-GR-NEXT:   0x0010:   Name: <corrupt>  Flags: none  Version: 0
 
 --- !ELF
 FileHeader:
@@ -312,3 +316,207 @@ Sections:
             Other: 0
 DynamicSymbols:
   - Name: foo
+
+## Check that we report a warning when sh_link references a non-existent section.
+
+# RUN: yaml2obj --docnum=6 %s -o %t6
+# RUN: llvm-readobj --sections -V %t6 2>&1 | FileCheck %s -DFILE=%t6 --implicit-check-not="warning:" --check-prefix=INVALID-LINK-LLVM
+# RUN: llvm-readelf --sections -V %t6 2>&1 | FileCheck %s -DFILE=%t6 --implicit-check-not="warning:" --check-prefix=INVALID-LINK-GNU
+
+# INVALID-LINK-LLVM:       VersionRequirements [
+# INVALID-LINK-LLVM-EMPTY:
+# INVALID-LINK-LLVM-NEXT:  warning: '[[FILE]]': invalid section linked to SHT_GNU_verneed section with index 1: invalid section index: 255
+# INVALID-LINK-LLVM-NEXT:   Dependency {
+# INVALID-LINK-LLVM-NEXT:     Version: 1
+# INVALID-LINK-LLVM-NEXT:     Count: 1
+# INVALID-LINK-LLVM-NEXT:     FileName: <corrupt vn_file: 1>
+# INVALID-LINK-LLVM-NEXT:     Entries [
+# INVALID-LINK-LLVM-NEXT:       Entry {
+# INVALID-LINK-LLVM-NEXT:         Hash: 0
+# INVALID-LINK-LLVM-NEXT:         Flags [ (0x0)
+# INVALID-LINK-LLVM-NEXT:         ]
+# INVALID-LINK-LLVM-NEXT:         Index: 0
+# INVALID-LINK-LLVM-NEXT:         Name: <corrupt>
+# INVALID-LINK-LLVM-NEXT:       }
+# INVALID-LINK-LLVM-NEXT:     ]
+# INVALID-LINK-LLVM-NEXT:   }
+# INVALID-LINK-LLVM-NEXT: ]
+
+# INVALID-LINK-GNU:       Version needs section '.gnu.version_r' contains 1 entries:
+# INVALID-LINK-GNU-EMPTY:
+# INVALID-LINK-GNU-NEXT:  warning: '[[FILE]]': invalid section linked to SHT_GNU_verneed section with index 1: invalid section index: 255
+# INVALID-LINK-GNU-NEXT:  Addr: 0000000000000000 Offset: 0x000040 Link: 255 (<corrupt>)
+# INVALID-LINK-GNU-NEXT:   0x0000: Version: 1 File: <corrupt vn_file: 1> Cnt: 1
+# INVALID-LINK-GNU-NEXT:   0x0010: Name: <corrupt> Flags: none Version: 0
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Name:  .gnu.version_r
+    Type:  SHT_GNU_verneed
+    Flags: [ SHF_ALLOC ]
+    Info:  1
+    Link:  0xFF
+    Dependencies:
+      - Version: 1
+        File:    foo
+        Entries:
+          - Name:  'foo'
+            Hash:  0
+            Flags: 0
+            Other: 0
+DynamicSymbols:
+  - Name: foo
+
+## Check that we report a warning when we can't read the content of the SHT_GNU_verneed section.
+
+# RUN: yaml2obj --docnum=7 %s -o %t7
+# RUN: llvm-readobj --sections -V %t7 2>&1 | FileCheck %s -DFILE=%t7 --check-prefix=INVALID-DATA
+# RUN: llvm-readelf --sections -V %t7 2>&1 | FileCheck %s -DFILE=%t7 --check-prefix=INVALID-DATA
+
+# INVALID-DATA: warning: '[[FILE]]': cannot read content of SHT_GNU_verneed section with index 1: section [index 1] has a sh_offset (0xffffffff) + sh_size (0x0) that cannot be represented
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Name:  .gnu.version_r
+    Type:  SHT_GNU_verneed
+    Flags: [ SHF_ALLOC ]
+    Info:  1
+    Link:  .dynstr
+    ShOffset: 0xFFFFFFFF
+## Triggers creation of the .dynstr.
+DynamicSymbols:
+  - Name: foo
+
+## Check that we report a warning when a SHT_GNU_verneed section contains a version dependency
+## that goes past the end of the section.
+
+# RUN: yaml2obj --docnum=8 %s -o %t8
+# RUN: llvm-readobj --sections -V %t8 2>&1 | FileCheck %s -DFILE=%t8 --check-prefix=DEP-PAST-END
+# RUN: llvm-readelf --sections -V %t8 2>&1 | FileCheck %s -DFILE=%t8 --check-prefix=DEP-PAST-END
+
+# DEP-PAST-END: warning: '[[FILE]]': invalid SHT_GNU_verneed section with index 1: version dependency 1 goes past the end of the section
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Name:  .gnu.version_r
+    Type:  SHT_GNU_verneed
+    Flags: [ SHF_ALLOC ]
+    Info:  1
+    Link:  .dynstr
+    ShSize: 0x1
+    Dependencies:
+      - Version: 1
+        File:    foo
+        Entries:
+          - Name:  'foo'
+            Hash:  0
+            Flags: 0
+            Other: 0
+DynamicSymbols:
+  - Name: foo
+
+## Check we report a warning when a version dependency is not correctly aligned in memory.
+
+# RUN: yaml2obj --docnum=9 %s -o %t9
+# RUN: llvm-readobj --sections -V %t9 2>&1 | FileCheck %s -DFILE=%t9 --check-prefix=MISALIGNED-DEP
+# RUN: llvm-readelf --sections -V %t9 2>&1 | FileCheck %s -DFILE=%t9 --check-prefix=MISALIGNED-DEP
+
+# MISALIGNED-DEP: warning: '[[FILE]]': invalid SHT_GNU_verneed section with index 1: found a misaligned version dependency entry at offset 0x0
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Type: Fill
+    Size: 0x1
+  - Name:  .gnu.version_r
+    Type:  SHT_GNU_verneed
+    Flags: [ SHF_ALLOC ]
+    Info:  1
+    Link:  .dynstr
+    Dependencies:
+      - Version: 1
+        File:    foo
+        Entries:
+          - Name:  'foo'
+            Hash:  0
+            Flags: 0
+            Other: 0
+DynamicSymbols:
+  - Name: foo
+
+## Check that we report a warning when a SHT_GNU_verneed section contains a dependency definition
+## that refers to an auxiliary entry that goes past the end of the section.
+
+# RUN: yaml2obj --docnum=10 %s -o %t10
+# RUN: llvm-readobj --sections -V %t10 2>&1 | FileCheck %s -DFILE=%t10 --check-prefix=AUX-PAST-END
+# RUN: llvm-readelf --sections -V %t10 2>&1 | FileCheck %s -DFILE=%t10 --check-prefix=AUX-PAST-END
+
+# AUX-PAST-END: warning: '[[FILE]]': invalid SHT_GNU_verneed section with index 1: version dependency 1 refers to an auxiliary entry that goes past the end of the section
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Name:  .gnu.version_r
+    Type:  SHT_GNU_verneed
+    Flags: [ SHF_ALLOC ]
+    Info:  1
+    Link:  .dynstr
+    ShSize: 21
+    Dependencies:
+      - Version: 1
+        File:    foo
+        Entries:
+          - Name:  'foo'
+            Hash:  0
+            Flags: 0
+            Other: 0
+DynamicSymbols:
+  - Name: foo
+
+## Check we report a warning when an auxiliary entry is not correctly aligned in memory.
+
+# RUN: yaml2obj %s --docnum=11 -o %t11
+# RUN: llvm-readobj -V %t11 2>&1 | FileCheck %s --check-prefix=MISALIGNED-AUX -DFILE=%t11
+# RUN: llvm-readelf -V %t11 2>&1 | FileCheck %s --check-prefix=MISALIGNED-AUX -DFILE=%t11
+
+# MISALIGNED-AUX: warning: '[[FILE]]': invalid SHT_GNU_verneed section with index 1: found a misaligned auxiliary entry at offset 0x11
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Name:  .gnu.version_r
+    Type:  SHT_GNU_verneed
+    Flags: [ SHF_ALLOC ]
+    Info:  1
+    Link:  .dynstr
+## The byte offset to the auxiliary entry is 0x11, i.e. it is not correctly aligned in memory.
+    Content: "0100010001000000110000000000000000000000"
+DynamicSymbols:
+  - Name: foo

diff  --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 51ea599f4be7..1031e0a181db 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -167,6 +167,23 @@ struct VerDef {
   std::string Name;
   std::vector<VerdAux> AuxV;
 };
+
+struct VernAux {
+  unsigned Hash;
+  unsigned Flags;
+  unsigned Other;
+  unsigned Offset;
+  std::string Name;
+};
+
+struct VerNeed {
+  unsigned Version;
+  unsigned Cnt;
+  unsigned Offset;
+  std::string File;
+  std::vector<VernAux> AuxV;
+};
+
 } // namespace
 
 template <typename ELFT> class ELFDumper : public ObjDumper {
@@ -345,25 +362,50 @@ template <typename ELFT> class ELFDumper : public ObjDumper {
 
   Expected<std::vector<VerDef>>
   getVersionDefinitions(const Elf_Shdr *Sec) const;
+  Expected<std::vector<VerNeed>>
+  getVersionDependencies(const Elf_Shdr *Sec) const;
 };
 
+static StringRef getSecTypeName(unsigned Type) {
+  if (Type == ELF::SHT_GNU_versym)
+    return "SHT_GNU_versym";
+  if (Type == ELF::SHT_GNU_verdef)
+    return "SHT_GNU_verdef";
+  if (Type == ELF::SHT_GNU_verneed)
+    return "SHT_GNU_verneed";
+  llvm_unreachable("unexpected section type");
+}
+
+template <class ELFT>
+static Expected<StringRef> getLinkAsStrtab(const ELFFile<ELFT> *Obj,
+                                           const typename ELFT::Shdr *Sec,
+                                           unsigned SecNdx) {
+  Expected<const typename ELFT::Shdr *> StrTabSecOrErr =
+      Obj->getSection(Sec->sh_link);
+  if (!StrTabSecOrErr)
+    return createError("invalid section linked to " +
+                       getSecTypeName(Sec->sh_type) + " section with index " +
+                       Twine(SecNdx) + ": " +
+                       toString(StrTabSecOrErr.takeError()));
+
+  Expected<StringRef> StrTabOrErr = Obj->getStringTable(*StrTabSecOrErr);
+  if (!StrTabOrErr)
+    return createError("invalid string table linked to " +
+                       getSecTypeName(Sec->sh_type) + " section with index " +
+                       Twine(SecNdx) + ": " +
+                       toString(StrTabOrErr.takeError()));
+  return *StrTabOrErr;
+}
+
 template <class ELFT>
 Expected<std::vector<VerDef>>
 ELFDumper<ELFT>::getVersionDefinitions(const Elf_Shdr *Sec) const {
   const ELFFile<ELFT> *Obj = ObjF->getELFFile();
   unsigned SecNdx = Sec - &cantFail(Obj->sections()).front();
 
-  Expected<const Elf_Shdr *> StrTabSecOrErr = Obj->getSection(Sec->sh_link);
-  if (!StrTabSecOrErr)
-    return createError(
-        "invalid section linked to SHT_GNU_verdef section with index " +
-        Twine(SecNdx) + ": " + toString(StrTabSecOrErr.takeError()));
-
-  Expected<StringRef> StrTabOrErr = Obj->getStringTable(*StrTabSecOrErr);
+  Expected<StringRef> StrTabOrErr = getLinkAsStrtab(Obj, Sec, SecNdx);
   if (!StrTabOrErr)
-    return createError(
-        "invalid string table linked to SHT_GNU_verdef section with index " +
-        Twine(SecNdx) + ": " + toString(StrTabOrErr.takeError()));
+    return StrTabOrErr.takeError();
 
   Expected<ArrayRef<uint8_t>> ContentsOrErr = Obj->getSectionContents(Sec);
   if (!ContentsOrErr)
@@ -448,6 +490,90 @@ ELFDumper<ELFT>::getVersionDefinitions(const Elf_Shdr *Sec) const {
   return Ret;
 }
 
+template <class ELFT>
+Expected<std::vector<VerNeed>>
+ELFDumper<ELFT>::getVersionDependencies(const Elf_Shdr *Sec) const {
+  const ELFFile<ELFT> *Obj = ObjF->getELFFile();
+  unsigned SecNdx = Sec - &cantFail(Obj->sections()).front();
+
+  StringRef StrTab;
+  Expected<StringRef> StrTabOrErr = getLinkAsStrtab(Obj, Sec, SecNdx);
+  if (!StrTabOrErr)
+    ELFDumperStyle->reportUniqueWarning(StrTabOrErr.takeError());
+  else
+    StrTab = *StrTabOrErr;
+
+  Expected<ArrayRef<uint8_t>> ContentsOrErr = Obj->getSectionContents(Sec);
+  if (!ContentsOrErr)
+    return createError(
+        "cannot read content of SHT_GNU_verneed section with index " +
+        Twine(SecNdx) + ": " + toString(ContentsOrErr.takeError()));
+
+  const uint8_t *Start = ContentsOrErr->data();
+  const uint8_t *End = Start + ContentsOrErr->size();
+  const uint8_t *VerneedBuf = Start;
+
+  std::vector<VerNeed> Ret;
+  for (unsigned I = 1; I <= /*VerneedNum=*/Sec->sh_info; ++I) {
+    if (VerneedBuf + sizeof(Elf_Verdef) > End)
+      return createError("invalid SHT_GNU_verneed section with index " +
+                         Twine(SecNdx) + ": version dependency " + Twine(I) +
+                         " goes past the end of the section");
+
+    if (uintptr_t(VerneedBuf) % sizeof(uint32_t) != 0)
+      return createError(
+          "invalid SHT_GNU_verneed section with index " + Twine(SecNdx) +
+          ": found a misaligned version dependency entry at offset 0x" +
+          Twine::utohexstr(VerneedBuf - Start));
+
+    const Elf_Verneed *Verneed =
+        reinterpret_cast<const Elf_Verneed *>(VerneedBuf);
+
+    VerNeed &VN = *Ret.emplace(Ret.end());
+    VN.Version = Verneed->vn_version;
+    VN.Cnt = Verneed->vn_cnt;
+    VN.Offset = VerneedBuf - Start;
+
+    if (Verneed->vn_file < StrTab.size())
+      VN.File = StrTab.drop_front(Verneed->vn_file);
+    else
+      VN.File = "<corrupt vn_file: " + to_string(Verneed->vn_file) + ">";
+
+    const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux;
+    for (unsigned J = 0; J < Verneed->vn_cnt; ++J) {
+      if (uintptr_t(VernauxBuf) % sizeof(uint32_t) != 0)
+        return createError("invalid SHT_GNU_verneed section with index " +
+                           Twine(SecNdx) +
+                           ": found a misaligned auxiliary entry at offset 0x" +
+                           Twine::utohexstr(VernauxBuf - Start));
+
+      if (VernauxBuf + sizeof(Elf_Vernaux) > End)
+        return createError(
+            "invalid SHT_GNU_verneed section with index " + Twine(SecNdx) +
+            ": version dependency " + Twine(I) +
+            " refers to an auxiliary entry that goes past the end "
+            "of the section");
+
+      const Elf_Vernaux *Vernaux =
+          reinterpret_cast<const Elf_Vernaux *>(VernauxBuf);
+
+      VernAux &Aux = *VN.AuxV.emplace(VN.AuxV.end());
+      Aux.Hash = Vernaux->vna_hash;
+      Aux.Flags = Vernaux->vna_flags;
+      Aux.Other = Vernaux->vna_other;
+      Aux.Offset = VernauxBuf - Start;
+      if (StrTab.size() <= Vernaux->vna_name)
+        Aux.Name = "<corrupt>";
+      else
+        Aux.Name = StrTab.drop_front(Vernaux->vna_name);
+
+      VernauxBuf += Vernaux->vna_next;
+    }
+    VerneedBuf += Verneed->vn_next;
+  }
+  return Ret;
+}
+
 template <class ELFT>
 void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) const {
   StringRef StrTable, SymtabName;
@@ -3946,9 +4072,10 @@ void GNUStyle<ELFT>::printGNUVersionSectionProlog(
     SymTabName =
         unwrapOrError(this->FileName, Obj->getSectionName(*SymTabOrErr));
   else
-    this->reportUniqueWarning(createError(
-        "invalid section linked to SHT_GNU_verdef section with index " +
-        Twine(SecNdx) + ": " + toString(SymTabOrErr.takeError())));
+    this->reportUniqueWarning(
+        createError("invalid section linked to " +
+                    getSecTypeName(Sec->sh_type) + " section with index " +
+                    Twine(SecNdx) + ": " + toString(SymTabOrErr.takeError())));
 
   OS << " Addr: " << format_hex_no_prefix(Sec->sh_addr, 16)
      << "  Offset: " << format_hex(Sec->sh_offset, 8)
@@ -4064,45 +4191,20 @@ void GNUStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj,
   unsigned VerneedNum = Sec->sh_info;
   printGNUVersionSectionProlog(Obj, Sec, "Version needs", VerneedNum);
 
-  ArrayRef<uint8_t> SecData =
-      unwrapOrError(this->FileName, Obj->getSectionContents(Sec));
-
-  const Elf_Shdr *StrTabSec =
-      unwrapOrError(this->FileName, Obj->getSection(Sec->sh_link));
-  StringRef StringTable = {
-      reinterpret_cast<const char *>(Obj->base() + StrTabSec->sh_offset),
-      (size_t)StrTabSec->sh_size};
-
-  const uint8_t *VerneedBuf = SecData.data();
-  for (unsigned I = 0; I < VerneedNum; ++I) {
-    const Elf_Verneed *Verneed =
-        reinterpret_cast<const Elf_Verneed *>(VerneedBuf);
-
-    StringRef File = StringTable.size() > Verneed->vn_file
-                         ? StringTable.drop_front(Verneed->vn_file)
-                         : "<invalid>";
-
-    OS << format("  0x%04x: Version: %u  File: %s  Cnt: %u\n",
-                 reinterpret_cast<const uint8_t *>(Verneed) - SecData.begin(),
-                 (unsigned)Verneed->vn_version, File.data(),
-                 (unsigned)Verneed->vn_cnt);
-
-    const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux;
-    for (unsigned J = 0; J < Verneed->vn_cnt; ++J) {
-      const Elf_Vernaux *Vernaux =
-          reinterpret_cast<const Elf_Vernaux *>(VernauxBuf);
-
-      StringRef Name = StringTable.size() > Vernaux->vna_name
-                           ? StringTable.drop_front(Vernaux->vna_name)
-                           : "<invalid>";
+  Expected<std::vector<VerNeed>> V =
+      this->dumper()->getVersionDependencies(Sec);
+  if (!V) {
+    this->reportUniqueWarning(V.takeError());
+    return;
+  }
 
-      OS << format("  0x%04x:   Name: %s  Flags: %s  Version: %u\n",
-                   reinterpret_cast<const uint8_t *>(Vernaux) - SecData.begin(),
-                   Name.data(), versionFlagToString(Vernaux->vna_flags).c_str(),
-                   (unsigned)Vernaux->vna_other);
-      VernauxBuf += Vernaux->vna_next;
-    }
-    VerneedBuf += Verneed->vn_next;
+  for (const VerNeed &VN : *V) {
+    OS << format("  0x%04x: Version: %u  File: %s  Cnt: %u\n", VN.Offset,
+                 VN.Version, VN.File.data(), VN.Cnt);
+    for (const VernAux &Aux : VN.AuxV)
+      OS << format("  0x%04x:   Name: %s  Flags: %s  Version: %u\n", Aux.Offset,
+                   Aux.Name.data(), versionFlagToString(Aux.Flags).c_str(),
+                   Aux.Other);
   }
   OS << '\n';
 }
@@ -5853,45 +5955,27 @@ void LLVMStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj,
   if (!Sec)
     return;
 
-  const uint8_t *SecData =
-      reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset);
-  const Elf_Shdr *StrTabSec =
-      unwrapOrError(this->FileName, Obj->getSection(Sec->sh_link));
-  StringRef StringTable = {
-      reinterpret_cast<const char *>(Obj->base() + StrTabSec->sh_offset),
-      (size_t)StrTabSec->sh_size};
+  Expected<std::vector<VerNeed>> V =
+      this->dumper()->getVersionDependencies(Sec);
+  if (!V) {
+    this->reportUniqueWarning(V.takeError());
+    return;
+  }
 
-  const uint8_t *VerneedBuf = SecData;
-  unsigned VerneedNum = Sec->sh_info;
-  for (unsigned I = 0; I < VerneedNum; ++I) {
-    const Elf_Verneed *Verneed =
-        reinterpret_cast<const Elf_Verneed *>(VerneedBuf);
+  for (const VerNeed &VN : *V) {
     DictScope Entry(W, "Dependency");
-    W.printNumber("Version", Verneed->vn_version);
-    W.printNumber("Count", Verneed->vn_cnt);
-
-    StringRef FileName = StringTable.size() > Verneed->vn_file
-                             ? StringTable.drop_front(Verneed->vn_file)
-                             : "<invalid>";
-    W.printString("FileName", FileName.data());
+    W.printNumber("Version", VN.Version);
+    W.printNumber("Count", VN.Cnt);
+    W.printString("FileName", VN.File.c_str());
 
-    const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux;
     ListScope L(W, "Entries");
-    for (unsigned J = 0; J < Verneed->vn_cnt; ++J) {
-      const Elf_Vernaux *Vernaux =
-          reinterpret_cast<const Elf_Vernaux *>(VernauxBuf);
+    for (const VernAux &Aux : VN.AuxV) {
       DictScope Entry(W, "Entry");
-      W.printNumber("Hash", Vernaux->vna_hash);
-      W.printFlags("Flags", Vernaux->vna_flags, makeArrayRef(SymVersionFlags));
-      W.printNumber("Index", Vernaux->vna_other);
-
-      StringRef Name = StringTable.size() > Vernaux->vna_name
-                           ? StringTable.drop_front(Vernaux->vna_name)
-                           : "<invalid>";
-      W.printString("Name", Name.data());
-      VernauxBuf += Vernaux->vna_next;
+      W.printNumber("Hash", Aux.Hash);
+      W.printFlags("Flags", Aux.Flags, makeArrayRef(SymVersionFlags));
+      W.printNumber("Index", Aux.Other);
+      W.printString("Name", Aux.Name.c_str());
     }
-    VerneedBuf += Verneed->vn_next;
   }
 }
 


        


More information about the llvm-commits mailing list