[llvm] 1af3cb5 - [llvm-readobj/libObject] - Allow dumping objects that has a broken SHT_SYMTAB_SHNDX section.

Georgii Rymar via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 3 00:40:18 PST 2020


Author: Georgii Rymar
Date: 2020-11-03T11:30:28+03:00
New Revision: 1af3cb5424d578d2c58bc55740075bfc2a0f119b

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

LOG: [llvm-readobj/libObject] - Allow dumping objects that has a broken SHT_SYMTAB_SHNDX section.

Currently it is impossible to create an instance of ELFObjectFile when the
SHT_SYMTAB_SHNDX can't be read. We error out when fail to parse the
SHT_SYMTAB_SHNDX section in the factory method.

This change delays reading of the SHT_SYMTAB_SHNDX section entries,
with it llvm-readobj is now able to work with such inputs.

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

Added: 
    

Modified: 
    llvm/include/llvm/Object/ELFObjectFile.h
    llvm/test/Object/invalid.test
    llvm/test/tools/llvm-readobj/ELF/symbol-shndx.test
    llvm/test/tools/obj2yaml/ELF/sht-symtab-shndx.yaml
    llvm/test/tools/yaml2obj/ELF/sht-symtab-shndx.yaml
    llvm/tools/llvm-readobj/ELFDumper.cpp
    llvm/unittests/Object/CMakeLists.txt
    llvm/unittests/Object/ELFObjectFileTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Object/ELFObjectFile.h b/llvm/include/llvm/Object/ELFObjectFile.h
index 5c12231331be..0f6604bd510a 100644
--- a/llvm/include/llvm/Object/ELFObjectFile.h
+++ b/llvm/include/llvm/Object/ELFObjectFile.h
@@ -249,14 +249,14 @@ template <class ELFT> class ELFObjectFile : public ELFObjectFileBase {
 private:
   ELFObjectFile(MemoryBufferRef Object, ELFFile<ELFT> EF,
                 const Elf_Shdr *DotDynSymSec, const Elf_Shdr *DotSymtabSec,
-                ArrayRef<Elf_Word> ShndxTable);
+                const Elf_Shdr *DotSymtabShndxSec);
 
 protected:
   ELFFile<ELFT> EF;
 
   const Elf_Shdr *DotDynSymSec = nullptr; // Dynamic symbol table section.
   const Elf_Shdr *DotSymtabSec = nullptr; // Symbol table section.
-  ArrayRef<Elf_Word> ShndxTable;
+  const Elf_Shdr *DotSymtabShndxSec = nullptr; // SHT_SYMTAB_SHNDX section.
 
   void moveSymbolNext(DataRefImpl &Symb) const override;
   Expected<StringRef> getSymbolName(DataRefImpl Symb) const override;
@@ -538,6 +538,16 @@ ELFObjectFile<ELFT>::getSymbolAddress(DataRefImpl Symb) const {
     return SymTabOrErr.takeError();
 
   if (EF.getHeader().e_type == ELF::ET_REL) {
+    ArrayRef<Elf_Word> ShndxTable;
+    if (DotSymtabShndxSec) {
+      // TODO: Test this error.
+      if (Expected<ArrayRef<Elf_Word>> ShndxTableOrErr =
+              EF.getSHNDXTable(*DotSymtabShndxSec))
+        ShndxTable = *ShndxTableOrErr;
+      else
+        return ShndxTableOrErr.takeError();
+    }
+
     Expected<const Elf_Shdr *> SectionOrErr =
         EF.getSection(*ESym, *SymTabOrErr, ShndxTable);
     if (!SectionOrErr)
@@ -684,6 +694,16 @@ template <class ELFT>
 Expected<section_iterator>
 ELFObjectFile<ELFT>::getSymbolSection(const Elf_Sym *ESym,
                                       const Elf_Shdr *SymTab) const {
+  ArrayRef<Elf_Word> ShndxTable;
+  if (DotSymtabShndxSec) {
+    // TODO: Test this error.
+    Expected<ArrayRef<Elf_Word>> ShndxTableOrErr =
+        EF.getSHNDXTable(*DotSymtabShndxSec);
+    if (!ShndxTableOrErr)
+      return ShndxTableOrErr.takeError();
+    ShndxTable = *ShndxTableOrErr;
+  }
+
   auto ESecOrErr = EF.getSection(*ESym, SymTab, ShndxTable);
   if (!ESecOrErr)
     return ESecOrErr.takeError();
@@ -984,7 +1004,7 @@ ELFObjectFile<ELFT>::create(MemoryBufferRef Object) {
 
   const Elf_Shdr *DotDynSymSec = nullptr;
   const Elf_Shdr *DotSymtabSec = nullptr;
-  ArrayRef<Elf_Word> ShndxTable;
+  const Elf_Shdr *DotSymtabShndxSec = nullptr;
   for (const Elf_Shdr &Sec : *SectionsOrErr) {
     switch (Sec.sh_type) {
     case ELF::SHT_DYNSYM: {
@@ -998,33 +1018,31 @@ ELFObjectFile<ELFT>::create(MemoryBufferRef Object) {
       break;
     }
     case ELF::SHT_SYMTAB_SHNDX: {
-      auto TableOrErr = EF.getSHNDXTable(Sec);
-      if (!TableOrErr)
-        return TableOrErr.takeError();
-      ShndxTable = *TableOrErr;
+      if (!DotSymtabShndxSec)
+        DotSymtabShndxSec = &Sec;
       break;
     }
     }
   }
   return ELFObjectFile<ELFT>(Object, EF, DotDynSymSec, DotSymtabSec,
-                             ShndxTable);
+                             DotSymtabShndxSec);
 }
 
 template <class ELFT>
 ELFObjectFile<ELFT>::ELFObjectFile(MemoryBufferRef Object, ELFFile<ELFT> EF,
                                    const Elf_Shdr *DotDynSymSec,
                                    const Elf_Shdr *DotSymtabSec,
-                                   ArrayRef<Elf_Word> ShndxTable)
+                                   const Elf_Shdr *DotSymtabShndx)
     : ELFObjectFileBase(
           getELFType(ELFT::TargetEndianness == support::little, ELFT::Is64Bits),
           Object),
       EF(EF), DotDynSymSec(DotDynSymSec), DotSymtabSec(DotSymtabSec),
-      ShndxTable(ShndxTable) {}
+      DotSymtabShndxSec(DotSymtabShndx) {}
 
 template <class ELFT>
 ELFObjectFile<ELFT>::ELFObjectFile(ELFObjectFile<ELFT> &&Other)
     : ELFObjectFile(Other.Data, Other.EF, Other.DotDynSymSec,
-                    Other.DotSymtabSec, Other.ShndxTable) {}
+                    Other.DotSymtabSec, Other.DotSymtabShndxSec) {}
 
 template <class ELFT>
 basic_symbol_iterator ELFObjectFile<ELFT>::symbol_begin() const {

diff  --git a/llvm/test/Object/invalid.test b/llvm/test/Object/invalid.test
index 8d9068a1ba07..b6bee98681b5 100644
--- a/llvm/test/Object/invalid.test
+++ b/llvm/test/Object/invalid.test
@@ -211,9 +211,9 @@ Sections:
 ## sizeof(.symtab_shndx) = (sizeof(.symtab) / entsize(.symtab)) * entsize(.symtab_shndx)
 
 # RUN: yaml2obj %s --docnum=11 -o %t11
-# RUN: not llvm-readobj --symbols %t11 2>&1 | FileCheck --check-prefix=INVALID-XINDEX-SIZE %s
+# RUN: llvm-readobj --symbols %t11 2>&1 | FileCheck --check-prefix=INVALID-XINDEX-SIZE %s
 
-# INVALID-XINDEX-SIZE: error: {{.*}}: SHT_SYMTAB_SHNDX has 2 entries, but the symbol table associated has 1
+# INVALID-XINDEX-SIZE: warning: {{.*}}: SHT_SYMTAB_SHNDX has 2 entries, but the symbol table associated has 1
 
 --- !ELF
 FileHeader:

diff  --git a/llvm/test/tools/llvm-readobj/ELF/symbol-shndx.test b/llvm/test/tools/llvm-readobj/ELF/symbol-shndx.test
index 1163b0b8fafa..62085b6c1883 100644
--- a/llvm/test/tools/llvm-readobj/ELF/symbol-shndx.test
+++ b/llvm/test/tools/llvm-readobj/ELF/symbol-shndx.test
@@ -254,3 +254,60 @@ Symbols:
     Index: SHN_XINDEX
   - Name:  no_shndx2
     Index: SHN_XINDEX
+
+## Check we can dump symbols even when the number of entries in the
+## SHT_SYMTAB_SHNDX section doesn't match the number of symbols in the symbol table.
+
+# RUN: yaml2obj --docnum=4 %s -o %t4
+# RUN: llvm-readelf --symbols %t4 2>&1 | FileCheck %s -DFILE=%t4 --check-prefix=SHNDX-ERR-GNU
+# RUN: llvm-readobj --symbols %t4 2>&1 | FileCheck %s -DFILE=%t4 --check-prefix=SHNDX-ERR-LLVM
+
+#       SHNDX-ERR-GNU: warning: '[[FILE]]': SHT_SYMTAB_SHNDX has 3 entries, but the symbol table associated has 2
+# SHNDX-ERR-GNU-EMPTY:
+#  SHNDX-ERR-GNU-NEXT: Symbol table '.symtab' contains 2 entries:
+#  SHNDX-ERR-GNU-NEXT:    Num:    Value          Size Type    Bind   Vis       Ndx Name
+#  SHNDX-ERR-GNU-NEXT:      0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT   UND
+#  SHNDX-ERR-GNU-NEXT: warning: '[[FILE]]': extended symbol index (1) is past the end of the SHT_SYMTAB_SHNDX section of size 0
+#  SHNDX-ERR-GNU-NEXT:      1: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT   RSV[0xffff]
+# SHNDX-ERR-GNU-EMPTY:
+#   SHNDX-ERR-GNU-NOT:{{.}}
+
+# SHNDX-ERR-LLVM: warning: '[[FILE]]': SHT_SYMTAB_SHNDX has 3 entries, but the symbol table associated has 2
+# SHNDX-ERR-LLVM:      Format: elf64-unknown
+# SHNDX-ERR-LLVM-NEXT: Arch: unknown
+# SHNDX-ERR-LLVM-NEXT: AddressSize: 64bit
+# SHNDX-ERR-LLVM-NEXT: LoadName: <Not found>
+# SHNDX-ERR-LLVM-NEXT: Symbols [
+# SHNDX-ERR-LLVM-NEXT:   Symbol {
+# SHNDX-ERR-LLVM-NEXT:     Name:  (0)
+# SHNDX-ERR-LLVM-NEXT:     Value: 0x0
+# SHNDX-ERR-LLVM-NEXT:     Size: 0
+# SHNDX-ERR-LLVM-NEXT:     Binding: Local (0x0)
+# SHNDX-ERR-LLVM-NEXT:     Type: None (0x0)
+# SHNDX-ERR-LLVM-NEXT:     Other: 0
+# SHNDX-ERR-LLVM-NEXT:     Section: Undefined (0x0)
+# SHNDX-ERR-LLVM-NEXT:   }
+# SHNDX-ERR-LLVM-NEXT:   Symbol {
+# SHNDX-ERR-LLVM-NEXT:     Name:  (0)
+# SHNDX-ERR-LLVM-NEXT:     Value: 0x0
+# SHNDX-ERR-LLVM-NEXT:     Size: 0
+# SHNDX-ERR-LLVM-NEXT:     Binding: Local (0x0)
+# SHNDX-ERR-LLVM-NEXT:     Type: None (0x0)
+# SHNDX-ERR-LLVM-NEXT:     Other: 0
+# SHNDX-ERR-LLVM-NEXT: warning: '[[FILE]]': extended symbol index (1) is past the end of the SHT_SYMTAB_SHNDX section of size 0
+# SHNDX-ERR-LLVM-NEXT:     Section: Reserved (0xFFFF)
+# SHNDX-ERR-LLVM-NEXT:   }
+# SHNDX-ERR-LLVM-NEXT: ]
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_REL
+Sections:
+  - Name:    .symtab_shndx
+    Type:    SHT_SYMTAB_SHNDX
+    Entries: [ 0, 1, 2 ]
+    Link:    .symtab
+Symbols:
+  - Index: SHN_XINDEX

diff  --git a/llvm/test/tools/obj2yaml/ELF/sht-symtab-shndx.yaml b/llvm/test/tools/obj2yaml/ELF/sht-symtab-shndx.yaml
index 27decbe76d92..2940e54cb435 100644
--- a/llvm/test/tools/obj2yaml/ELF/sht-symtab-shndx.yaml
+++ b/llvm/test/tools/obj2yaml/ELF/sht-symtab-shndx.yaml
@@ -143,7 +143,7 @@ Symbols: []
 # RUN: yaml2obj --docnum=6 %s -o %t6
 # RUN: not obj2yaml %t6 2>&1 | FileCheck %s -DFILE=%t6 --check-prefix=CASE6
 
-# CASE6: Error reading file: [[FILE]]: SHT_SYMTAB_SHNDX section is linked with SHT_PROGBITS section (expected SHT_SYMTAB/SHT_DYNSYM)
+# CASE6: Error reading file: [[FILE]]: only SHT_SYMTAB_SHNDX associated with SHT_SYMTAB are supported
 
 --- !ELF
 FileHeader:

diff  --git a/llvm/test/tools/yaml2obj/ELF/sht-symtab-shndx.yaml b/llvm/test/tools/yaml2obj/ELF/sht-symtab-shndx.yaml
index a442c24522e7..4c185810820d 100644
--- a/llvm/test/tools/yaml2obj/ELF/sht-symtab-shndx.yaml
+++ b/llvm/test/tools/yaml2obj/ELF/sht-symtab-shndx.yaml
@@ -107,9 +107,9 @@ Symbols:
 ## Check we can set a custom sh_entsize for SHT_SYMTAB_SHNDX section.
 
 # RUN: yaml2obj --docnum=5 %s -o %t5
-# RUN: not llvm-readelf -S 2>&1 %t5 | FileCheck %s -DFILE=%t5 --check-prefix=CASE5
+# RUN: llvm-readelf -S 2>&1 %t5 | FileCheck %s -DFILE=%t5 --check-prefix=CASE5
 
-# CASE5: error: '[[FILE]]': section [index 1] has an invalid sh_entsize: 2
+# CASE5: warning: '[[FILE]]': section [index 1] has an invalid sh_entsize: 2
 
 --- !ELF
 FileHeader:

diff  --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 4b8e987d99b7..470ba491a89b 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -2026,7 +2026,10 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> &O,
       }
       break;
     case ELF::SHT_SYMTAB_SHNDX:
-      ShndxTable = unwrapOrError(ObjF.getFileName(), Obj.getSHNDXTable(Sec));
+      if (Expected<ArrayRef<Elf_Word>> ShndxTableOrErr = Obj.getSHNDXTable(Sec))
+        ShndxTable = *ShndxTableOrErr;
+      else
+        this->reportUniqueWarning(ShndxTableOrErr.takeError());
       break;
     case ELF::SHT_GNU_versym:
       if (!SymbolVersionSection)

diff  --git a/llvm/unittests/Object/CMakeLists.txt b/llvm/unittests/Object/CMakeLists.txt
index b263e03396fd..559d02ea0ae5 100644
--- a/llvm/unittests/Object/CMakeLists.txt
+++ b/llvm/unittests/Object/CMakeLists.txt
@@ -1,6 +1,7 @@
 set(LLVM_LINK_COMPONENTS
   BinaryFormat
   Object
+  ObjectYAML
   )
 
 add_llvm_unittest(ObjectTests

diff  --git a/llvm/unittests/Object/ELFObjectFileTest.cpp b/llvm/unittests/Object/ELFObjectFileTest.cpp
index ebbbae0af093..5b7a29891493 100644
--- a/llvm/unittests/Object/ELFObjectFileTest.cpp
+++ b/llvm/unittests/Object/ELFObjectFileTest.cpp
@@ -8,6 +8,8 @@
 
 #include "llvm/Object/ELFObjectFile.h"
 #include "llvm/Support/MemoryBuffer.h"
+#include "llvm/ObjectYAML/yaml2obj.h"
+#include "llvm/Support/YAMLTraits.h"
 #include "llvm/Testing/Support/Error.h"
 #include "gtest/gtest.h"
 
@@ -291,9 +293,38 @@ TEST(ELFObjectFileTest, MachineTestForCSKY) {
     checkFormatAndArch(D, Formats[I++], Triple::csky);
 }
 
-
-
 // ELF relative relocation type test.
 TEST(ELFObjectFileTest, RelativeRelocationTypeTest) {
   EXPECT_EQ(ELF::R_CKCORE_RELATIVE, getELFRelativeRelocationType(ELF::EM_CSKY));
 }
+
+template <class ELFT>
+static Expected<ELFObjectFile<ELFT>> toBinary(SmallVectorImpl<char> &Storage,
+                                              StringRef Yaml) {
+  raw_svector_ostream OS(Storage);
+  yaml::Input YIn(Yaml);
+  if (!yaml::convertYAML(YIn, OS, [](const Twine &Msg) {}))
+    return createStringError(std::errc::invalid_argument,
+                             "unable to convert YAML");
+  return ELFObjectFile<ELFT>::create(MemoryBufferRef(OS.str(), "dummyELF"));
+}
+
+// Check we are able to create an ELFObjectFile even when the content of the
+// SHT_SYMTAB_SHNDX section can't be read properly.
+TEST(ELFObjectFileTest, InvalidSymtabShndxTest) {
+  SmallString<0> Storage;
+  Expected<ELFObjectFile<ELF64LE>> ExpectedFile = toBinary<ELF64LE>(Storage, R"(
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_REL
+Sections:
+  - Name:    .symtab_shndx
+    Type:    SHT_SYMTAB_SHNDX
+    Entries: [ 0 ]
+    ShSize: 0xFFFFFFFF
+)");
+
+  ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
+}


        


More information about the llvm-commits mailing list