Index: include/llvm/Object/ELF.h =================================================================== --- include/llvm/Object/ELF.h +++ include/llvm/Object/ELF.h @@ -64,6 +64,8 @@ return "[unknown index]"; } +static Error defaultWarningHandler(const Twine &Msg) { return createError(Msg); } + template class ELFFile { public: @@ -95,6 +97,13 @@ using Elf_Relr_Range = typename ELFT::RelrRange; using Elf_Phdr_Range = typename ELFT::PhdrRange; + // This is a callback that can be passed to a number of functions. + // It can be used to ignore non-critical errors (warnings), what is + // useful for dumpers, like llvm-readobj. + // It accepts a warning message string and returns a success + // when the warning should be ignored or a error otherwise. + using WarningHandler = llvm::function_ref; + const uint8_t *base() const { return Buf.bytes_begin(); } size_t getBufSize() const { return Buf.size(); } @@ -114,7 +123,9 @@ template Expected getEntry(const Elf_Shdr *Section, uint32_t Entry) const; - Expected getStringTable(const Elf_Shdr *Section) const; + Expected + getStringTable(const Elf_Shdr *Section, + WarningHandler WarnHandler = &defaultWarningHandler) const; Expected getStringTableForSymtab(const Elf_Shdr &Section) const; Expected getStringTableForSymtab(const Elf_Shdr &Section, Elf_Shdr_Range Sections) const; @@ -261,7 +272,9 @@ return make_range(notes_begin(Shdr, Err), notes_end()); } - Expected getSectionStringTable(Elf_Shdr_Range Sections) const; + Expected getSectionStringTable( + Elf_Shdr_Range Sections, + WarningHandler WarnHandler = &defaultWarningHandler) const; Expected getSectionIndex(const Elf_Sym *Sym, Elf_Sym_Range Syms, ArrayRef ShndxTable) const; Expected getSection(const Elf_Sym *Sym, @@ -276,7 +289,9 @@ Expected getSymbol(const Elf_Shdr *Sec, uint32_t Index) const; - Expected getSectionName(const Elf_Shdr *Section) const; + Expected + getSectionName(const Elf_Shdr *Section, + WarningHandler WarnHandler = &defaultWarningHandler) const; Expected getSectionName(const Elf_Shdr *Section, StringRef DotShstrtab) const; template @@ -459,7 +474,8 @@ template Expected -ELFFile::getSectionStringTable(Elf_Shdr_Range Sections) const { +ELFFile::getSectionStringTable(Elf_Shdr_Range Sections, + WarningHandler WarnHandler) const { uint32_t Index = getHeader()->e_shstrndx; if (Index == ELF::SHN_XINDEX) Index = Sections[0].sh_link; @@ -470,7 +486,7 @@ if (Index >= Sections.size()) return createError("section header string table index " + Twine(Index) + " does not exist"); - return getStringTable(&Sections[Index]); + return getStringTable(&Sections[Index], WarnHandler); } template ELFFile::ELFFile(StringRef Object) : Buf(Object) {} @@ -587,13 +603,16 @@ template Expected -ELFFile::getStringTable(const Elf_Shdr *Section) const { +ELFFile::getStringTable(const Elf_Shdr *Section, + WarningHandler WarnHandler) const { if (Section->sh_type != ELF::SHT_STRTAB) - return createError("invalid sh_type for string table section " + - getSecIndexForError(this, Section) + - ": expected SHT_STRTAB, but got " + - object::getELFSectionTypeName(getHeader()->e_machine, - Section->sh_type)); + if (Error E = WarnHandler("invalid sh_type for string table section " + + getSecIndexForError(this, Section) + + ": expected SHT_STRTAB, but got " + + object::getELFSectionTypeName( + getHeader()->e_machine, Section->sh_type))) + return std::move(E); + auto V = getSectionContentsAsArray(Section); if (!V) return V.takeError(); @@ -668,11 +687,12 @@ template Expected -ELFFile::getSectionName(const Elf_Shdr *Section) const { +ELFFile::getSectionName(const Elf_Shdr *Section, + WarningHandler WarnHandler) const { auto SectionsOrErr = sections(); if (!SectionsOrErr) return SectionsOrErr.takeError(); - auto Table = getSectionStringTable(*SectionsOrErr); + auto Table = getSectionStringTable(*SectionsOrErr, WarnHandler); if (!Table) return Table.takeError(); return getSectionName(Section, *Table); Index: test/tools/llvm-readobj/elf-invalid-shstrndx.test =================================================================== --- test/tools/llvm-readobj/elf-invalid-shstrndx.test +++ test/tools/llvm-readobj/elf-invalid-shstrndx.test @@ -1,6 +1,6 @@ # RUN: yaml2obj %s -o %t -# RUN: not llvm-readelf --headers -S 2>&1 %t | FileCheck %s -DFILE=%t --check-prefix=GNU -# RUN: not llvm-readobj --headers -S 2>&1 %t | FileCheck %s -DFILE=%t --check-prefix=LLVM +# RUN: not llvm-readelf --headers -S 2>&1 %t | FileCheck %s --check-prefix=GNU +# RUN: not llvm-readobj --headers -S 2>&1 %t | FileCheck %s --check-prefix=LLVM # GNU: ELF Header: # GNU: Section header string table index: 255 @@ -8,14 +8,14 @@ # GNU: Section Headers: # GNU-NEXT: [Nr] Name # GNU-EMPTY: -# GNU-NEXT: error: '[[FILE]]': section header string table index 255 does not exist +# GNU-NEXT: error: section header string table index 255 does not exist # LLVM: ElfHeader { # LLVM: StringTableSectionIndex: 255 # LLVM-NEXT: } # LLVM-NEXT: Sections [ # LLVM-EMPTY: -# LLVM-NEXT: error: '[[FILE]]': section header string table index 255 does not exist +# LLVM-NEXT: error: section header string table index 255 does not exist --- !ELF FileHeader: Index: test/tools/llvm-readobj/elf-wrong-shstrtab-type.test =================================================================== --- test/tools/llvm-readobj/elf-wrong-shstrtab-type.test +++ test/tools/llvm-readobj/elf-wrong-shstrtab-type.test @@ -2,14 +2,18 @@ ## a .shstrtab section does not have a SHT_STRTAB type. # RUN: yaml2obj %s -o %t1 -# RUN: llvm-readobj -S %t1 | FileCheck %s --check-prefix LLVM -# RUN: llvm-readelf -S %t1 | FileCheck %s --check-prefix GNU +# RUN: llvm-readobj -S %t1 2>&1 | FileCheck %s --implicit-check-not warning --check-prefix LLVM +# RUN: llvm-readelf -S %t1 2>&1 | FileCheck %s --implicit-check-not warning --check-prefix GNU -# LLVM: Name: .shstrtab -# LLVM-NEXT: Type: SHT_PROGBITS +# LLVM: warning: invalid sh_type for string table section [index 1]: expected SHT_STRTAB, but got SHT_PROGBITS +# LLVM: Section { +# LLVM: Name: .shstrtab +# LLVM: Type: SHT_PROGBITS -# GNU: [Nr] Name Type -# GNU: [ 1] .shstrtab PROGBITS +# GNU: Section Headers: +# GNU: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# GNU: warning: invalid sh_type for string table section [index 1]: expected SHT_STRTAB, but got SHT_PROGBITS +# GNU: [ 1] .shstrtab PROGBITS 0000000000000000 000140 00001b 00 0 0 0 --- !ELF FileHeader: Index: tools/llvm-readobj/ELFDumper.cpp =================================================================== --- tools/llvm-readobj/ELFDumper.cpp +++ tools/llvm-readobj/ELFDumper.cpp @@ -59,6 +59,7 @@ #include #include #include +#include #include #include #include @@ -348,7 +349,16 @@ using Elf_Shdr = typename ELFT::Shdr; using Elf_Sym = typename ELFT::Sym; - DumpStyle(ELFDumper *Dumper) : Dumper(Dumper) {} + DumpStyle(ELFDumper *Dumper) : Dumper(Dumper) { + // Dumper reports all non-critical errors as a warnings. + // It does not print the same warning more than once. + WarningHandler = [this](const Twine &Msg) { + if (Warnings.insert(Msg.str()).second) + reportWarning(Msg); + return Error::success(); + }; + } + virtual ~DumpStyle() = default; virtual void printFileHeaders(const ELFFile *Obj) = 0; @@ -383,6 +393,10 @@ virtual void printMipsPLT(const MipsGOTParser &Parser) = 0; const ELFDumper *dumper() const { return Dumper; } +protected: + std::function WarningHandler; + std::set Warnings; + private: const ELFDumper *Dumper; }; @@ -3005,26 +3019,6 @@ return ""; } -template -static StringRef getSectionName(const typename ELFT::Shdr &Sec, - const ELFObjectFile &ElfObj, - ArrayRef Sections) { - const ELFFile &Obj = *ElfObj.getELFFile(); - uint32_t Index = Obj.getHeader()->e_shstrndx; - if (Index == ELF::SHN_XINDEX) - Index = Sections[0].sh_link; - if (!Index) // no section string table. - return ""; - // TODO: Test a case when the sh_link of the section with index 0 is broken. - if (Index >= Sections.size()) - reportError(ElfObj.getFileName(), - createError("section header string table index " + - Twine(Index) + " does not exist")); - StringRef Data = toStringRef(unwrapOrError( - Obj.template getSectionContentsAsArray(&Sections[Index]))); - return unwrapOrError(Obj.getSectionName(&Sec, Data)); -} - template void GNUStyle::printSectionHeaders(const ELFO *Obj) { unsigned Bias = ELFT::Is64Bits ? 0 : 8; @@ -3042,11 +3036,11 @@ printField(F); OS << "\n"; - const ELFObjectFile *ElfObj = this->dumper()->getElfObject(); size_t SectionIndex = 0; for (const Elf_Shdr &Sec : Sections) { Fields[0].Str = to_string(SectionIndex); - Fields[1].Str = getSectionName(Sec, *ElfObj, Sections); + Fields[1].Str = + unwrapOrError(Obj->getSectionName(&Sec, this->WarningHandler)); Fields[2].Str = getSectionTypeString(Obj->getHeader()->e_machine, Sec.sh_type); Fields[3].Str = @@ -4593,9 +4587,9 @@ int SectionIndex = -1; ArrayRef Sections = unwrapOrError(Obj->sections()); - const ELFObjectFile *ElfObj = this->dumper()->getElfObject(); for (const Elf_Shdr &Sec : Sections) { - StringRef Name = getSectionName(Sec, *ElfObj, Sections); + StringRef Name = + unwrapOrError(Obj->getSectionName(&Sec, this->WarningHandler)); DictScope SectionD(W, "Section"); W.printNumber("Index", ++SectionIndex); W.printNumber("Name", Name, Sec.sh_name);