[llvm] 9d4bbe8 - [llvm-readelf/llvm-readobj] - Improve dumping of broken versioning sections.

Georgii Rymar via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 31 02:17:49 PDT 2019


Author: Georgii Rymar
Date: 2019-10-31T12:12:17+03:00
New Revision: 9d4bbe88915a3a878d8501369f2ce8093a194921

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

LOG: [llvm-readelf/llvm-readobj] - Improve dumping of broken versioning sections.

This updates the elf-invalid-versioning.test test case:
makes a cleanup, adds llvm-readobj calls and fixes 2
crash/assert issues I've found (test cases are provided).

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

Added: 
    

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

Removed: 
    


################################################################################
diff  --git a/llvm/test/tools/llvm-readobj/elf-invalid-versioning.test b/llvm/test/tools/llvm-readobj/elf-invalid-versioning.test
index e963d6905c2d..c7107daf200e 100644
--- a/llvm/test/tools/llvm-readobj/elf-invalid-versioning.test
+++ b/llvm/test/tools/llvm-readobj/elf-invalid-versioning.test
@@ -1,42 +1,311 @@
-# RUN: yaml2obj %s -o %t
-# RUN: llvm-readelf -V %t | FileCheck %s --check-prefix=INVALID
+## Here we test how llvm-readelf/llvm-readobj behave when inputs have
+## invalid versioning sections.
 
-# INVALID:      Version symbols section '.gnu.version' contains 2 entries:
-# INVALID-NEXT:  Addr: 0000000000200210  Offset: 0x000040  Link: 5 (.dynsym)
-# INVALID-NEXT:   000:   0 (*local*)       3 (*invalid*)
+## In the first case we have a SHT_GNU_versym section that refers to
+## a version listed in a SHT_GNU_verneed section. That version has an
+## empty name, making it invalid.
+
+# RUN: yaml2obj --docnum=1 %s -o %t1
+# RUN: llvm-readelf -V %t1 | FileCheck %s --check-prefix=GNU-VERNEED-NAME
+# RUN: llvm-readobj -V %t1 | FileCheck %s --check-prefix=LLVM-VERNEED-NAME
+
+# GNU-VERNEED-NAME:      Version symbols section '.gnu.version' contains 2 entries:
+# GNU-VERNEED-NAME-NEXT:  Addr: 0000000000200210  Offset: 0x000040  Link: 5 (.dynsym)
+# GNU-VERNEED-NAME-NEXT:   000:   0 (*local*)       2 (*invalid*)
+
+# GNU-VERNEED-NAME:      Version needs section '.gnu.version_r' contains 1 entries:
+# GNU-VERNEED-NAME-NEXT:  Addr: 0000000000000000  Offset: 0x000044  Link: 6 (.dynstr)
+# GNU-VERNEED-NAME-NEXT:   0x0000: Version: 1  File: somefile  Cnt: 1
+# GNU-VERNEED-NAME-NEXT:   0x0010:   Name:   Flags: none  Version: 2
+
+# LLVM-VERNEED-NAME:      VersionSymbols [
+# LLVM-VERNEED-NAME:        Symbol {
+# LLVM-VERNEED-NAME-NEXT:     Version: 0
+# LLVM-VERNEED-NAME-NEXT:     Name:
+# LLVM-VERNEED-NAME-NEXT:   }
+# LLVM-VERNEED-NAME-NEXT:   Symbol {
+# LLVM-VERNEED-NAME-NEXT:     Version: 2
+# LLVM-VERNEED-NAME-NEXT:     Name: foo
+# LLVM-VERNEED-NAME-NEXT:   }
+# LLVM-VERNEED-NAME-NEXT: ]
+
+# LLVM-VERNEED-NAME:      VersionRequirements [
+# LLVM-VERNEED-NAME-NEXT:   Dependency {
+# LLVM-VERNEED-NAME-NEXT:     Version: 1
+# LLVM-VERNEED-NAME-NEXT:     Count: 1
+# LLVM-VERNEED-NAME-NEXT:     FileName: somefile
+# LLVM-VERNEED-NAME-NEXT:     Entries [
+# LLVM-VERNEED-NAME-NEXT:       Entry {
+# LLVM-VERNEED-NAME-NEXT:         Hash:  0
+# LLVM-VERNEED-NAME-NEXT:         Flags: 0x0
+# LLVM-VERNEED-NAME-NEXT:         Index: 2
+# LLVM-VERNEED-NAME-NEXT:         Name: {{$}}
+# LLVM-VERNEED-NAME-NEXT:       }
+# LLVM-VERNEED-NAME-NEXT:     ]
+# LLVM-VERNEED-NAME-NEXT:   }
+# LLVM-VERNEED-NAME-NEXT: ]
 
 --- !ELF
 FileHeader:
-  Class:             ELFCLASS64
-  Data:              ELFDATA2LSB
-  Type:              ET_EXEC
-  Machine:           EM_X86_64
-  Entry:             0x0000000000201000
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
 Sections:
-  - Name:            .gnu.version
-    Type:            SHT_GNU_versym
-    Flags:           [ SHF_ALLOC ]
-    Address:         0x0000000000200210
-    Link:            .dynsym
-    AddressAlign:    0x0000000000000002
-    EntSize:         0x0000000000000002
-    Entries:         [ 0, 3 ]
-  - Name:            .gnu.version_r
-    Type:            SHT_GNU_verneed
-    Flags:           [ SHF_ALLOC ]
-    Address:         0x0000000000200250
-    Link:            .dynstr
-    AddressAlign:    0x0000000000000004
-    Info:            0x0000000000000001
+  - Name:    .gnu.version
+    Type:    SHT_GNU_versym
+    Flags:   [ SHF_ALLOC ]
+    Address: 0x200210
+    Link:    .dynsym
+    Entries: [ 0, 2 ]
+  - Name:  .gnu.version_r
+    Type:  SHT_GNU_verneed
+    Flags: [ SHF_ALLOC ]
+    Link:  .dynstr
+    Info:  1
+    AddressAlign: 4
     Dependencies:
-      - Version:     1
-        File:        somefile
+      - Version:   1
+        File:      somefile
         Entries:
-          - Name:    ''         # invalid name
-            Hash:    1937
-            Flags:   233
-            Other:   3
+          - Name:  '' ## invalid name
+            Hash:  0
+            Flags: 0
+            Other: 2
 DynamicSymbols:
-  - Name:          f
-    Binding:       STB_GLOBAL
+  - Name:    foo
+    Binding: STB_GLOBAL
 ...
+
+## In this case SHT_GNU_verneed is not linked to a dynamic string table. We check we handle
+## 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
+
+# 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
+
+# LLVM-NOLINK:      VersionSymbols [
+# LLVM-NOLINK:        Symbol {
+# LLVM-NOLINK-NEXT:     Version: 0
+# LLVM-NOLINK-NEXT:     Name:
+# LLVM-NOLINK-NEXT:   }
+# LLVM-NOLINK-NEXT:   Symbol {
+# LLVM-NOLINK-NEXT:     Version: 2
+# LLVM-NOLINK-NEXT:     Name: foo at bar
+# LLVM-NOLINK-NEXT:   }
+# LLVM-NOLINK-NEXT: ]
+
+# LLVM-NOLINK:      VersionRequirements [
+# LLVM-NOLINK-NEXT:   Dependency {
+# LLVM-NOLINK-NEXT:     Version: 1
+# LLVM-NOLINK-NEXT:     Count: 1
+# LLVM-NOLINK-NEXT:     FileName: <invalid>
+# LLVM-NOLINK-NEXT:     Entries [
+# LLVM-NOLINK-NEXT:       Entry {
+# LLVM-NOLINK-NEXT:         Hash: 0
+# LLVM-NOLINK-NEXT:         Flags: 0
+# LLVM-NOLINK-NEXT:         Index: 2
+# LLVM-NOLINK-NEXT:         Name: <invalid>
+# LLVM-NOLINK-NEXT:       }
+# LLVM-NOLINK-NEXT:     ]
+# LLVM-NOLINK-NEXT:   }
+# LLVM-NOLINK-NEXT: ]
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Name:    .gnu.version
+    Type:    SHT_GNU_versym
+    Flags:   [ SHF_ALLOC ]
+    Link:    .dynsym
+    Entries: [ 0, 2 ]
+  - Name:  .gnu.version_r
+    Type:  SHT_GNU_verneed
+    Flags: [ SHF_ALLOC ]
+    Link:  0
+    Info:  1
+    AddressAlign: 4
+    Dependencies:
+      - Version: 1
+        File:    somefile
+        Entries:
+          - Name:  'bar'
+            Hash:  0
+            Flags: 0
+            Other: 2
+DynamicSymbols:
+  - Name:    foo
+    Binding: STB_GLOBAL
+
+## We can't parse misaligned auxiliary version records.
+## Here we have a SHT_GNU_verneed section aligned by 1 byte.
+## This makes the first auxiliary record offset % 4 be non-zero.
+
+# RUN: yaml2obj --docnum=3 %s -o %t3
+# RUN: not llvm-readelf -V %t3 2>&1 | FileCheck %s -DFILE=%t3 --check-prefix=BROKEN-AUX
+# RUN: not llvm-readobj -V %t3 2>&1 | FileCheck %s -DFILE=%t3 --check-prefix=BROKEN-AUX
+
+# BROKEN-AUX: error: '[[FILE]]': SHT_GNU_verneed: the vn_aux field of the entry with index 0 references a misaligned auxiliary record
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Name:    .gnu.version
+    Type:    SHT_GNU_versym
+    Flags:   [ SHF_ALLOC ]
+    Link:    .dynsym
+    Entries: [ 2 ]
+  - Name:  .gnu.version_r
+    Type:  SHT_GNU_verneed
+    Flags: [ SHF_ALLOC ]
+    Info:  1
+    AddressAlign: 1
+    Dependencies:
+      - Version: 1
+        File:    somefile
+        Entries:
+          - Name:  'bar'
+            Hash:  0
+            Flags: 0
+            Other: 2
+DynamicSymbols:
+  - Name: foo
+
+## 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.
+##
+## We set the version dependency vn_file field to the offset of string 'foo' in
+## the .dynstr, which is 1. We create a custom string table .mystrtab of size 1
+## and link it with the .gnu.version_r section. For the vna_name we use the same trick.
+
+# RUN: yaml2obj --docnum=4 %s -o %t4
+# RUN: llvm-readobj --sections --section-data -V %t4 | FileCheck %s --check-prefix=LLVM-OFFSET-EQ
+# RUN: llvm-readelf --sections -V %t4 | FileCheck %s --check-prefix=GNU-OFFSET-EQ
+
+# LLVM-OFFSET-EQ: Name: .mystrtab
+# LLVM-OFFSET-EQ: Size:
+# LLVM-OFFSET-EQ-SAME:  1
+
+# LLVM-OFFSET-EQ:      Name: .dynstr
+# LLVM-OFFSET-EQ:      SectionData (
+# LLVM-OFFSET-EQ-NEXT:   0000: 00666F6F 00 |.foo.|
+# LLVM-OFFSET-EQ-NEXT: )
+
+# LLVM-OFFSET-EQ:      VersionRequirements [
+# 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:     Entries [
+# LLVM-OFFSET-EQ-NEXT:       Entry {
+# LLVM-OFFSET-EQ-NEXT:         Hash: 0
+# LLVM-OFFSET-EQ-NEXT:         Flags: 0x0
+# LLVM-OFFSET-EQ-NEXT:         Index: 0
+# LLVM-OFFSET-EQ-NEXT:         Name: <invalid>
+# LLVM-OFFSET-EQ-NEXT:       }
+# LLVM-OFFSET-EQ-NEXT:     ]
+# LLVM-OFFSET-EQ-NEXT:   }
+# LLVM-OFFSET-EQ-NEXT: ]
+
+# 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
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Name: .mystrtab
+    Type: SHT_STRTAB
+    Content: "00"
+  - Name:  .gnu.version_r
+    Type:  SHT_GNU_verneed
+    Flags: [ SHF_ALLOC ]
+    Info:  1
+    Link:  .mystrtab
+    AddressAlign: 4
+    Dependencies:
+      - Version: 1
+        File:    foo
+        Entries:
+          - Name:  'foo'
+            Hash:  0
+            Flags: 0
+            Other: 0
+DynamicSymbols:
+  - Name: foo
+
+## Here we check that we can properly dump the case when a dependency file name
+## and/or a dependency name string offset is greater than the string table size.
+##
+# RUN: yaml2obj --docnum=5 %s -o %t5
+# RUN: llvm-readobj --sections -V %t5 | FileCheck %s --check-prefix=LLVM-OFFSET-GR
+# RUN: llvm-readelf --sections -V %t5 | FileCheck %s --check-prefix=GNU-OFFSET-GR
+
+# LLVM-OFFSET-GR:      VersionRequirements [
+# 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:     Entries [
+# LLVM-OFFSET-GR-NEXT:       Entry {
+# LLVM-OFFSET-GR-NEXT:         Hash: 0
+# LLVM-OFFSET-GR-NEXT:         Flags: 0x0
+# LLVM-OFFSET-GR-NEXT:         Index: 0
+# LLVM-OFFSET-GR-NEXT:         Name: <invalid>
+# LLVM-OFFSET-GR-NEXT:       }
+# LLVM-OFFSET-GR-NEXT:     ]
+# LLVM-OFFSET-GR-NEXT:   }
+# LLVM-OFFSET-GR-NEXT: ]
+
+# 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
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Name: .mystrtab
+    Type: SHT_STRTAB
+    Content: ""
+  - Name:  .gnu.version_r
+    Type:  SHT_GNU_verneed
+    Flags: [ SHF_ALLOC ]
+    Info:  1
+    Link:  .mystrtab
+    AddressAlign: 4
+    Dependencies:
+      - Version: 1
+        File:    foo
+        Entries:
+          - Name:  'foo'
+            Hash:  0
+            Flags: 0
+            Other: 0
+DynamicSymbols:
+  - Name: foo

diff  --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 57144882c4b4..d9e50e7508d3 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -667,6 +667,13 @@ void ELFDumper<ELFT>::LoadVersionNeeds(const Elf_Shdr *Sec) const {
       if (VernauxBuf + sizeof(Elf_Vernaux) > VerneedEnd)
         report_fatal_error("Section ended unexpected while scanning auxiliary "
                            "version needed records.");
+      if ((ptr
diff _t)VernauxBuf % sizeof(uint32_t) != 0)
+        reportError(createError("SHT_GNU_verneed: the vn_aux field of the "
+                                "entry with index " +
+                                Twine(VerneedIndex) +
+                                " references a misaligned auxiliary record"),
+                    ObjF->getFileName());
+
       const Elf_Vernaux *Vernaux =
           reinterpret_cast<const Elf_Vernaux *>(VernauxBuf);
       size_t Index = Vernaux->vna_other & ELF::VERSYM_VERSION;
@@ -3921,10 +3928,13 @@ void GNUStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj,
     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,
-                 StringTable.drop_front(Verneed->vn_file).data(),
+                 (unsigned)Verneed->vn_version, File.data(),
                  (unsigned)Verneed->vn_cnt);
 
     const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux;
@@ -3932,10 +3942,13 @@ void GNUStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj,
       const Elf_Vernaux *Vernaux =
           reinterpret_cast<const Elf_Vernaux *>(VernauxBuf);
 
+      StringRef Name = StringTable.size() > Vernaux->vna_name
+                           ? StringTable.drop_front(Vernaux->vna_name)
+                           : "<invalid>";
+
       OS << format("  0x%04x:   Name: %s  Flags: %s  Version: %u\n",
                    reinterpret_cast<const uint8_t *>(Vernaux) - SecData.begin(),
-                   StringTable.drop_front(Vernaux->vna_name).data(),
-                   versionFlagToString(Vernaux->vna_flags).c_str(),
+                   Name.data(), versionFlagToString(Vernaux->vna_flags).c_str(),
                    (unsigned)Vernaux->vna_other);
       VernauxBuf += Vernaux->vna_next;
     }
@@ -5693,8 +5706,11 @@ void LLVMStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj,
 
   const uint8_t *SecData =
       reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset);
-  const Elf_Shdr *StrTab =
+  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;
   unsigned VerneedNum = Sec->sh_info;
@@ -5704,9 +5720,11 @@ void LLVMStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj,
     DictScope Entry(W, "Dependency");
     W.printNumber("Version", Verneed->vn_version);
     W.printNumber("Count", Verneed->vn_cnt);
-    W.printString("FileName",
-                  StringRef(reinterpret_cast<const char *>(
-                      Obj->base() + StrTab->sh_offset + Verneed->vn_file)));
+
+    StringRef FileName = StringTable.size() > Verneed->vn_file
+                             ? StringTable.drop_front(Verneed->vn_file)
+                             : "<invalid>";
+    W.printString("FileName", FileName.data());
 
     const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux;
     ListScope L(W, "Entries");
@@ -5717,9 +5735,11 @@ void LLVMStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj,
       W.printNumber("Hash", Vernaux->vna_hash);
       W.printEnum("Flags", Vernaux->vna_flags, makeArrayRef(SymVersionFlags));
       W.printNumber("Index", Vernaux->vna_other);
-      W.printString("Name",
-                    StringRef(reinterpret_cast<const char *>(
-                        Obj->base() + StrTab->sh_offset + Vernaux->vna_name)));
+
+      StringRef Name = StringTable.size() > Vernaux->vna_name
+                           ? StringTable.drop_front(Vernaux->vna_name)
+                           : "<invalid>";
+      W.printString("Name", Name.data());
       VernauxBuf += Vernaux->vna_next;
     }
     VerneedBuf += Verneed->vn_next;


        


More information about the llvm-commits mailing list