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 @@ -235,13 +235,14 @@ # INVALID-PH-ENTSIZE: error: '[[FILE]]': invalid e_phentsize: 12336 -## Check that llvm-readobj reports an error when we have no SHT_SYMTAB_SHNDX section, +## Check that llvm-readobj reports a warning when we have no SHT_SYMTAB_SHNDX section, ## but have a symbol referencing it. -# RUN: not llvm-readobj --symbols %p/Inputs/invalid-ext-symtab-index.elf-x86-64 2>&1 | \ +# RUN: llvm-readobj --symbols %p/Inputs/invalid-ext-symtab-index.elf-x86-64 2>&1 | \ # RUN: FileCheck -DFILE=%p/Inputs/invalid-ext-symtab-index.elf-x86-64 --check-prefix=INVALID-EXT-SYMTAB-INDEX %s -# INVALID-EXT-SYMTAB-INDEX: error: '[[FILE]]': extended symbol index (0) is past the end of the SHT_SYMTAB_SHNDX section of size 0 +# INVALID-EXT-SYMTAB-INDEX: warning: '[[FILE]]': extended symbol index (0) is past the end of the SHT_SYMTAB_SHNDX section of size 0 +# INVALID-EXT-SYMTAB-INDEX: Section: Reserved (0xFFFF) ## Check that llvm-readobj reports an error if a relocation section ## has a broken sh_offset (past the end of the file). diff --git a/llvm/test/tools/llvm-readobj/elf-section-symbols.test b/llvm/test/tools/llvm-readobj/elf-section-symbols.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/elf-section-symbols.test @@ -0,0 +1,85 @@ +## ELF section symbols use the section names when printing. This test verifies +## this and also that appropriate things are printed if the section is somehow +## invalid. + +# RUN: yaml2obj %s -o %t1 +# RUN: llvm-readobj %t1 --symbols 2> %t.llvm.err1 | FileCheck %s --check-prefix=LLVM1 +# RUN: FileCheck %s --input-file %t.llvm.err1 --check-prefix=WARN1 --implicit-check-not=warning +# RUN: llvm-readelf %t1 --symbols 2> %t.gnu.err1 | FileCheck %s --check-prefix=GNU1 +# RUN: FileCheck %s --input-file %t.gnu.err1 --check-prefix=WARN1 --implicit-check-not=warning + +# LLVM1: Name: (0) +# LLVM1: Name: .foo (0) +# LLVM1: Name:
(0) +# LLVM1: Name: .bar (0) +# LLVM1: Name:
(0) + +# GNU1: Symbol table '.symtab' contains 5 entries: +# GNU1-NEXT: Num: {{.*}} Type {{.*}} Ndx Name +# GNU1-NEXT: 0: {{.*}} NOTYPE {{.*}} UND {{$}} +# GNU1-NEXT: 1: {{.*}} SECTION {{.*}} 1 .foo +# GNU1-NEXT: 2: {{.*}} SECTION {{.*}} 67
+# GNU1-NEXT: 3: {{.*}} SECTION {{.*}} 2 .bar +# GNU1-NEXT: 4: {{.*}} SECTION {{.*}} 66
+ +# WARN1: warning: '{{.*}}.tmp1': invalid section index: 67 +# WARN1: warning: '{{.*}}.tmp1': invalid section index: 66 + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_386 +Sections: + - Name: .foo + Type: SHT_PROGBITS + - Name: .bar + Type: SHT_PROGBITS + - Name: .symtab_shndx + Type: SHT_SYMTAB_SHNDX + Link: .symtab + Entries: [ 0, 0, 0, 2, 0x42 ] +Symbols: + - Name: "" + Section: .foo + Type: STT_SECTION + - Name: "" + Index: 0x43 + Type: STT_SECTION + # Section symbol via SHT_SYMTAB_SHNDX. + - Name: "" + Index: SHN_XINDEX + Type: STT_SECTION + # Section symbol via SHT_SYMTAB_SHNDX with invalid index. + - Name: "" + Index: SHN_XINDEX + Type: STT_SECTION + +# RUN: yaml2obj %s --docnum=2 -o %t2 +# RUN: llvm-readobj %t2 --symbols 2> %t.llvm.err2 | FileCheck %s --check-prefix=LLVM2 +# RUN: FileCheck %s --input-file %t.llvm.err2 --check-prefix=WARN2 --implicit-check-not=warning +# RUN: llvm-readelf %t2 --symbols 2> %t.gnu.err2 | FileCheck %s --check-prefix=GNU2 +# RUN: FileCheck %s --input-file %t.gnu.err2 --check-prefix=WARN2 --implicit-check-not=warning + +# LLVM2: Name: (0) +# LLVM2: Name: (0) + +# GNU2: Symbol table '.symtab' contains 2 entries: +# GNU2-NEXT: Num: {{.*}} Type {{.*}} Ndx Name +# GNU2-NEXT: 0: {{.*}} NOTYPE {{.*}} UND {{$}} +# GNU2-NEXT: 1: {{.*}} SECTION {{.*}} RSV[0xffff] + +# WARN2: warning: '{{.*}}.tmp2': extended symbol index (1) is past the end of the SHT_SYMTAB_SHNDX section of size 0 + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_386 +Symbols: + # Section symbol via SHT_SYMTAB_SHNDX when SHT_SYMTAB_SHNDX is missing. + - Name: "" + Index: SHN_XINDEX + Type: STT_SECTION 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 @@ -1,104 +1,187 @@ -# Show that llvm-readobj prints symbol shndxes correctly, for valid indexes, -# invalid indexes (i.e. section indexes that don't correspond to a real -# section), reserved values and processor/os-specific index values, for both GNU -# and LLVM styles. - -# RUN: yaml2obj --docnum=1 %s > %t1 -# RUN: llvm-readobj --symbols %t1 | FileCheck %s --check-prefix=LLVM1 -# RUN: llvm-readelf --symbols %t1 | FileCheck %s --check-prefix=GNU1 - -# llvm-readobj doesn't accept shndx values that are not valid section indexes -# for LLVM style, so only test GNU output in this case. -# RUN: yaml2obj --docnum=2 %s > %t2 -# RUN: llvm-readelf --symbols %t2 | FileCheck %s --check-prefix=GNU2 - -# LLVM1: Name: undef -# LLVM1: Section: -# LLVM1-SAME: Undefined (0x0) -# LLVM1: Name: normal -# LLVM1: Section: -# LLVM1-SAME: .text (0x1) -# LLVM1: Name: common -# LLVM1: Section: -# LLVM1-SAME: Common (0xFFF2) -# LLVM1: Name: absolute -# LLVM1: Section: -# LLVM1-SAME: Absolute (0xFFF1) -# LLVM1: Name: proc -# LLVM1: Section: -# LLVM1-SAME: Processor Specific (0xFF01) -# LLVM1: Name: os -# LLVM1: Section: -# LLVM1-SAME: Operating System Specific (0xFF21) -# LLVM1: Name: reserved -# LLVM1: Section: -# LLVM1-SAME: Reserved (0xFFFE) -# LLVM1: Name: xindex -# LLVM1: Section: -# LLVM1: .text (0x1) - -# GNU1: Symbol table '.symtab' contains 9 entries: -# GNU1-NEXT: Num: {{.*}} Ndx Name -# GNU1-NEXT: 0: {{.*}} UND -# GNU1-NEXT: 1: {{.*}} UND undef -# GNU1-NEXT: 2: {{.*}} 1 normal -# GNU1-NEXT: 3: {{.*}} COM common -# GNU1-NEXT: 4: {{.*}} ABS absolute -# GNU1-NEXT: 5: {{.*}} PRC[0xff01] proc -# GNU1-NEXT: 6: {{.*}} OS[0xff21] os -# GNU1-NEXT: 7: {{.*}} RSV[0xfffe] reserved -# GNU1-NEXT: 8: {{.*}} 1 xindex - -# GNU2: Symbol table '.symtab' contains 2 entries: -# GNU2-NEXT: Num: {{.*}} Ndx Name -# GNU2-NEXT: 0: {{.*}} UND -# GNU2-NEXT: 1: {{.*}} 66 bad - ---- !ELF -FileHeader: - Class: ELFCLASS32 - Data: ELFDATA2LSB - Type: ET_REL - Machine: EM_386 -Sections: - - Name: .text - Type: SHT_PROGBITS - - Name: .symtab_shndx - Type: SHT_SYMTAB_SHNDX - Link: .symtab - Entries: [ 0, 0, 0, 0, 0, 0, 0, 0, 1 ] -Symbols: - - Name: undef - Binding: STB_GLOBAL - - Name: normal - Section: .text - Binding: STB_GLOBAL - - Name: common - Index: SHN_COMMON - Binding: STB_GLOBAL - - Name: absolute - Index: SHN_ABS - Binding: STB_GLOBAL - - Name: proc - Index: 0xff01 - Binding: STB_GLOBAL - - Name: os - Index: 0xff21 - Binding: STB_GLOBAL - - Name: reserved - Index: 0xfffe - Binding: STB_GLOBAL - - Name: xindex - Index: SHN_XINDEX - Binding: STB_GLOBAL - ---- !ELF -FileHeader: - Class: ELFCLASS32 - Data: ELFDATA2LSB - Type: ET_REL - Machine: EM_386 -Symbols: - - Name: bad - Index: 0x42 - Binding: STB_GLOBAL +## Show that llvm-readobj prints symbol shndxes correctly, for valid indexes, +## invalid indexes (i.e. section indexes that don't correspond to a real +## section), reserved values and processor/os-specific index values, for both GNU +## and LLVM styles. + +# RUN: yaml2obj --docnum=1 %s > %t1 +# RUN: llvm-readobj --symbols %t1 | FileCheck %s --check-prefix=LLVM1 +# RUN: llvm-readelf --symbols %t1 | FileCheck %s --check-prefix=GNU1 + +# LLVM1: Name: undef +# LLVM1: Section: +# LLVM1-SAME: Undefined (0x0) +# LLVM1: Name: normal +# LLVM1: Section: +# LLVM1-SAME: .text (0x1) +# LLVM1: Name: common +# LLVM1: Section: +# LLVM1-SAME: Common (0xFFF2) +# LLVM1: Name: absolute +# LLVM1: Section: +# LLVM1-SAME: Absolute (0xFFF1) +# LLVM1: Name: proc +# LLVM1: Section: +# LLVM1-SAME: Processor Specific (0xFF01) +# LLVM1: Name: os +# LLVM1: Section: +# LLVM1-SAME: Operating System Specific (0xFF21) +# LLVM1: Name: reserved +# LLVM1: Section: +# LLVM1-SAME: Reserved (0xFFFE) +# LLVM1: Name: xindex +# LLVM1: Section: +# LLVM1: .text (0x1) + +# GNU1: Symbol table '.symtab' contains 9 entries: +# GNU1-NEXT: Num: {{.*}} Ndx Name +# GNU1-NEXT: 0: {{.*}} UND +# GNU1-NEXT: 1: {{.*}} UND undef +# GNU1-NEXT: 2: {{.*}} 1 normal +# GNU1-NEXT: 3: {{.*}} COM common +# GNU1-NEXT: 4: {{.*}} ABS absolute +# GNU1-NEXT: 5: {{.*}} PRC[0xff01] proc +# GNU1-NEXT: 6: {{.*}} OS[0xff21] os +# GNU1-NEXT: 7: {{.*}} RSV[0xfffe] reserved +# GNU1-NEXT: 8: {{.*}} 1 xindex + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_386 +Sections: + - Name: .text + Type: SHT_PROGBITS + - Name: .symtab_shndx + Type: SHT_SYMTAB_SHNDX + Link: .symtab + Entries: [ 0, 0, 0, 0, 0, 0, 0, 0, 1 ] +Symbols: + - Name: undef + Binding: STB_GLOBAL + - Name: normal + Section: .text + Binding: STB_GLOBAL + - Name: common + Index: SHN_COMMON + Binding: STB_GLOBAL + - Name: absolute + Index: SHN_ABS + Binding: STB_GLOBAL + - Name: proc + Index: 0xff01 + Binding: STB_GLOBAL + - Name: os + Index: 0xff21 + Binding: STB_GLOBAL + - Name: reserved + Index: 0xfffe + Binding: STB_GLOBAL + - Name: xindex + Index: SHN_XINDEX + Binding: STB_GLOBAL + +## In this case, the index does not correspond to a real section. Check that GNU +## style just prints the section index as normal and LLVM style prints a warning +## (but only once for each warning). +# RUN: yaml2obj --docnum=2 %s > %t2 +# RUN: llvm-readobj --symbols %t2 2> %t2.llvm.err | FileCheck %s --check-prefix=LLVM2 +# RUN: FileCheck %s --input-file=%t2.llvm.err --check-prefix=BAD-SHNDX --implicit-check-not=warning +# RUN: llvm-readelf --symbols %t2 2> %t2.gnu.err | FileCheck %s --check-prefix=GNU2 +# RUN: FileCheck %s --input-file=%t2.gnu.err --allow-empty --implicit-check-not={{.}} + +# LLVM2: Name: bad +# LLVM2: Section: +# LLVM2-SAME: (0x42) +# LLVM2: Name: bad2 +# LLVM2: Section: +# LLVM2-SAME: (0x42) +# LLVM2: Name: bad3 +# LLVM2: Section: +# LLVM2-SAME: (0x43) +# LLVM2: Name: invalid_shndx +# LLVM2: Section: +# LLVM2-SAME: (0x9) +# LLVM2: Name: invalid_shndx2 +# LLVM2: Section: +# LLVM2-SAME: (0x9) +# LLVM2: Name: invalid_shndx3 +# LLVM2: Section: +# LLVM2-SAME: (0xA) + +# GNU2: Symbol table '.symtab' contains 7 entries: +# GNU2-NEXT: Num: {{.*}} Ndx Name +# GNU2-NEXT: 0: {{.*}} UND +# GNU2-NEXT: 1: {{.*}} 66 bad +# GNU2-NEXT: 2: {{.*}} 66 bad2 +# GNU2-NEXT: 3: {{.*}} 67 bad3 +# GNU2-NEXT: 4: {{.*}} 9 invalid_shndx +# GNU2-NEXT: 5: {{.*}} 9 invalid_shndx2 +# GNU2-NEXT: 6: {{.*}} 10 invalid_shndx3 + +# BAD-SHNDX: warning: '{{.*}}tmp2': invalid section index: 66 +# BAD-SHNDX: warning: '{{.*}}tmp2': invalid section index: 67 +# BAD-SHNDX: warning: '{{.*}}tmp2': invalid section index: 9 +# BAD-SHNDX: warning: '{{.*}}tmp2': invalid section index: 10 + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_386 +Sections: + - Name: .symtab_shndx + Type: SHT_SYMTAB_SHNDX + Link: .symtab + Entries: [ 0, 0, 0, 0, 9, 9, 10 ] +Symbols: + - Name: bad + Index: 0x42 + - Name: bad2 + Index: 0x42 + - Name: bad3 + Index: 0x43 + - Name: invalid_shndx + Index: SHN_XINDEX + - Name: invalid_shndx2 + Index: SHN_XINDEX + - Name: invalid_shndx3 + Index: SHN_XINDEX + +## In this case, the symtab shndx section is missing, so symbols with section +## indexes of SHN_XINDEX print as Reserved symbols. +# RUN: yaml2obj --docnum=3 %s > %t3 +# RUN: llvm-readobj --symbols %t3 2> %t3.llvm.err | FileCheck %s --check-prefix=LLVM3 +# RUN: FileCheck %s --input-file=%t3.llvm.err --check-prefix=NO-SYMTAB-SHNDX --implicit-check-not=warning +# RUN: llvm-readelf --symbols %t3 2> %t3.gnu.err | FileCheck %s --check-prefix=GNU3 +# RUN: FileCheck %s --input-file=%t3.gnu.err --check-prefix=NO-SYMTAB-SHNDX --implicit-check-not=warning + +# LLVM3: Name: no_shndx +# LLVM3: Section: +# LLVM3-SAME: Reserved (0xFFFF) +# LLVM3: Name: no_shndx2 +# LLVM3: Section: +# LLVM3-SAME: Reserved (0xFFFF) + +# GNU3: Symbol table '.symtab' contains 3 entries: +# GNU3-NEXT: Num: {{.*}} Ndx Name +# GNU3-NEXT: 0: {{.*}} UND +# GNU3-NEXT: 1: {{.*}} RSV[0xffff] no_shndx +# GNU3-NEXT: 2: {{.*}} RSV[0xffff] no_shndx2 + +# NO-SYMTAB-SHNDX: warning: '{{.*}}tmp3': extended symbol index (1) is past the end of the SHT_SYMTAB_SHNDX section of size 0 +# NO-SYMTAB-SHNDX: warning: '{{.*}}tmp3': extended symbol index (2) is past the end of the SHT_SYMTAB_SHNDX section of size 0 + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_386 +Symbols: + - Name: no_shndx + Index: SHN_XINDEX + - Name: no_shndx2 + Index: SHN_XINDEX 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 @@ -433,6 +433,8 @@ virtual void printMipsABIFlags(const ELFObjectFile *Obj) = 0; const ELFDumper *dumper() const { return Dumper; } + void reportUniqueWarning(Error Err) const; + protected: std::function WarningHandler; StringRef FileName; @@ -556,6 +558,14 @@ void printSectionMapping(const ELFO *Obj); }; +template +void DumpStyle::reportUniqueWarning(Error Err) const { + handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) { + cantFail(WarningHandler(EI.message()), + "WarningHandler should always return ErrorSuccess"); + }); +} + template class LLVMStyle : public DumpStyle { public: TYPEDEF_ELF_TYPES(ELFT) @@ -824,10 +834,18 @@ if (SymbolName.empty() && Symbol->getType() == ELF::STT_SECTION) { Elf_Sym_Range Syms = unwrapOrError( ObjF->getFileName(), ObjF->getELFFile()->symbols(DotSymtabSec)); - unsigned SectionIndex = unwrapOrError( - ObjF->getFileName(), getSymbolSectionIndex(Symbol, Syms.begin())); - return unwrapOrError(ObjF->getFileName(), - getSymbolSectionName(Symbol, SectionIndex)); + Expected SectionIndex = + getSymbolSectionIndex(Symbol, Syms.begin()); + if (!SectionIndex) { + ELFDumperStyle->reportUniqueWarning(SectionIndex.takeError()); + return ""; + } + Expected NameOrErr = getSymbolSectionName(Symbol, *SectionIndex); + if (!NameOrErr) { + ELFDumperStyle->reportUniqueWarning(NameOrErr.takeError()); + return ("
").str(); + } + return *NameOrErr; } if (!IsDynamic) @@ -3298,12 +3316,18 @@ return "ABS"; case ELF::SHN_COMMON: return "COM"; - case ELF::SHN_XINDEX: - return to_string(format_decimal( - unwrapOrError(this->FileName, - object::getExtendedSymbolTableIndex( - Symbol, FirstSym, this->dumper()->getShndxTable())), - 3)); + case ELF::SHN_XINDEX: { + Expected IndexOrErr = object::getExtendedSymbolTableIndex( + Symbol, FirstSym, this->dumper()->getShndxTable()); + if (!IndexOrErr) { + assert(Symbol->st_shndx == SHN_XINDEX && + "getSymbolSectionIndex should only fail due to an invalid " + "SHT_SYMTAB_SHNDX table/reference"); + reportUniqueWarning(IndexOrErr.takeError()); + return "RSV[0xffff]"; + } + return to_string(format_decimal(*IndexOrErr, 3)); + } default: // Find if: // Processor specific @@ -5454,11 +5478,25 @@ template void LLVMStyle::printSymbolSection(const Elf_Sym *Symbol, const Elf_Sym *First) { - unsigned SectionIndex = unwrapOrError( - FileName, this->dumper()->getSymbolSectionIndex(Symbol, First)); - StringRef SectionName = unwrapOrError( - FileName, this->dumper()->getSymbolSectionName(Symbol, SectionIndex)); - W.printHex("Section", SectionName, SectionIndex); + Expected SectionIndex = + this->dumper()->getSymbolSectionIndex(Symbol, First); + if (!SectionIndex) { + assert(Symbol->st_shndx == SHN_XINDEX && + "getSymbolSectionIndex should only fail due to an invalid " + "SHT_SYMTAB_SHNDX table/reference"); + reportUniqueWarning(SectionIndex.takeError()); + W.printHex("Section", "Reserved", SHN_XINDEX); + return; + } + + Expected SectionName = + this->dumper()->getSymbolSectionName(Symbol, *SectionIndex); + if (!SectionName) { + reportUniqueWarning(SectionName.takeError()); + W.printHex("Section", "", *SectionIndex); + } else { + W.printHex("Section", *SectionName, *SectionIndex); + } } template