diff --git a/llvm/include/llvm/Object/ELFObjectFile.h b/llvm/include/llvm/Object/ELFObjectFile.h --- a/llvm/include/llvm/Object/ELFObjectFile.h +++ b/llvm/include/llvm/Object/ELFObjectFile.h @@ -249,14 +249,14 @@ private: ELFObjectFile(MemoryBufferRef Object, ELFFile EF, const Elf_Shdr *DotDynSymSec, const Elf_Shdr *DotSymtabSec, - ArrayRef ShndxTable); + const Elf_Shdr *DotSymtabShndxSec); protected: ELFFile EF; const Elf_Shdr *DotDynSymSec = nullptr; // Dynamic symbol table section. const Elf_Shdr *DotSymtabSec = nullptr; // Symbol table section. - ArrayRef ShndxTable; + const Elf_Shdr *DotSymtabShndxSec = nullptr; // SHT_SYMTAB_SHNDX section. void moveSymbolNext(DataRefImpl &Symb) const override; Expected getSymbolName(DataRefImpl Symb) const override; @@ -538,6 +538,16 @@ return SymTabOrErr.takeError(); if (EF.getHeader().e_type == ELF::ET_REL) { + ArrayRef ShndxTable; + if (DotSymtabShndxSec) { + // TODO: Test this error. + if (Expected> ShndxTableOrErr = + EF.getSHNDXTable(*DotSymtabShndxSec)) + ShndxTable = *ShndxTableOrErr; + else + return ShndxTableOrErr.takeError(); + } + Expected SectionOrErr = EF.getSection(*ESym, *SymTabOrErr, ShndxTable); if (!SectionOrErr) @@ -684,6 +694,16 @@ Expected ELFObjectFile::getSymbolSection(const Elf_Sym *ESym, const Elf_Shdr *SymTab) const { + ArrayRef ShndxTable; + if (DotSymtabShndxSec) { + // TODO: Test this error. + Expected> 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 @@ const Elf_Shdr *DotDynSymSec = nullptr; const Elf_Shdr *DotSymtabSec = nullptr; - ArrayRef ShndxTable; + const Elf_Shdr *DotSymtabShndxSec = nullptr; for (const Elf_Shdr &Sec : *SectionsOrErr) { switch (Sec.sh_type) { case ELF::SHT_DYNSYM: { @@ -998,33 +1018,31 @@ 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(Object, EF, DotDynSymSec, DotSymtabSec, - ShndxTable); + DotSymtabShndxSec); } template ELFObjectFile::ELFObjectFile(MemoryBufferRef Object, ELFFile EF, const Elf_Shdr *DotDynSymSec, const Elf_Shdr *DotSymtabSec, - ArrayRef 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 ELFObjectFile::ELFObjectFile(ELFObjectFile &&Other) : ELFObjectFile(Other.Data, Other.EF, Other.DotDynSymSec, - Other.DotSymtabSec, Other.ShndxTable) {} + Other.DotSymtabSec, Other.DotSymtabShndxSec) {} template basic_symbol_iterator ELFObjectFile::symbol_begin() const { diff --git a/llvm/test/Object/invalid.test b/llvm/test/Object/invalid.test --- a/llvm/test/Object/invalid.test +++ b/llvm/test/Object/invalid.test @@ -211,9 +211,9 @@ ## 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 --- a/llvm/test/tools/llvm-readobj/ELF/symbol-shndx.test +++ b/llvm/test/tools/llvm-readobj/ELF/symbol-shndx.test @@ -254,3 +254,60 @@ 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: +# 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 --- a/llvm/test/tools/obj2yaml/ELF/sht-symtab-shndx.yaml +++ b/llvm/test/tools/obj2yaml/ELF/sht-symtab-shndx.yaml @@ -143,7 +143,7 @@ # 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 --- a/llvm/test/tools/yaml2obj/ELF/sht-symtab-shndx.yaml +++ b/llvm/test/tools/yaml2obj/ELF/sht-symtab-shndx.yaml @@ -107,9 +107,9 @@ ## 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 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -2026,7 +2026,10 @@ } break; case ELF::SHT_SYMTAB_SHNDX: - ShndxTable = unwrapOrError(ObjF.getFileName(), Obj.getSHNDXTable(Sec)); + if (Expected> 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 --- 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 --- 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 @@ 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 +static Expected> toBinary(SmallVectorImpl &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::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> ExpectedFile = toBinary(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()); +}