return "[unknown index]";
}
+static Error defaultWarningHandler(const Twine &Msg) { return createError(Msg); }
+
template <class ELFT>
class ELFFile {
public:
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), which is
+ // useful for dumpers, like llvm-readobj.
+ // It accepts a warning message string and returns a success
+ // when the warning should be ignored or an error otherwise.
+ using WarningHandler = llvm::function_ref<Error(const Twine &Msg)>;
+
const uint8_t *base() const { return Buf.bytes_begin(); }
size_t getBufSize() const { return Buf.size(); }
template <typename T>
Expected<const T *> getEntry(const Elf_Shdr *Section, uint32_t Entry) const;
- Expected<StringRef> getStringTable(const Elf_Shdr *Section) const;
+ Expected<StringRef>
+ getStringTable(const Elf_Shdr *Section,
+ WarningHandler WarnHandler = &defaultWarningHandler) const;
Expected<StringRef> getStringTableForSymtab(const Elf_Shdr &Section) const;
Expected<StringRef> getStringTableForSymtab(const Elf_Shdr &Section,
Elf_Shdr_Range Sections) const;
return make_range(notes_begin(Shdr, Err), notes_end());
}
- Expected<StringRef> getSectionStringTable(Elf_Shdr_Range Sections) const;
+ Expected<StringRef> getSectionStringTable(
+ Elf_Shdr_Range Sections,
+ WarningHandler WarnHandler = &defaultWarningHandler) const;
Expected<uint32_t> getSectionIndex(const Elf_Sym *Sym, Elf_Sym_Range Syms,
ArrayRef<Elf_Word> ShndxTable) const;
Expected<const Elf_Shdr *> getSection(const Elf_Sym *Sym,
Expected<const Elf_Sym *> getSymbol(const Elf_Shdr *Sec,
uint32_t Index) const;
- Expected<StringRef> getSectionName(const Elf_Shdr *Section) const;
+ Expected<StringRef>
+ getSectionName(const Elf_Shdr *Section,
+ WarningHandler WarnHandler = &defaultWarningHandler) const;
Expected<StringRef> getSectionName(const Elf_Shdr *Section,
StringRef DotShstrtab) const;
template <typename T>
template <class ELFT>
Expected<StringRef>
-ELFFile<ELFT>::getSectionStringTable(Elf_Shdr_Range Sections) const {
+ELFFile<ELFT>::getSectionStringTable(Elf_Shdr_Range Sections,
+ WarningHandler WarnHandler) const {
uint32_t Index = getHeader()->e_shstrndx;
if (Index == ELF::SHN_XINDEX)
Index = Sections[0].sh_link;
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 <class ELFT> ELFFile<ELFT>::ELFFile(StringRef Object) : Buf(Object) {}
template <class ELFT>
Expected<StringRef>
-ELFFile<ELFT>::getStringTable(const Elf_Shdr *Section) const {
+ELFFile<ELFT>::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<char>(Section);
if (!V)
return V.takeError();
template <class ELFT>
Expected<StringRef>
-ELFFile<ELFT>::getSectionName(const Elf_Shdr *Section) const {
+ELFFile<ELFT>::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);
## overflows the section name string table.
# RUN: yaml2obj %s --docnum=17 -o %t17
-# RUN: not llvm-readobj --sections %t17 2>&1 | FileCheck --check-prefix=BROKEN-SECNAME %s
+# RUN: not llvm-readobj --sections %t17 2>&1 | FileCheck -DFILE=%t17 --check-prefix=BROKEN-SECNAME %s
-## BROKEN-SECNAME: error: a section [index 1] has an invalid sh_name (0x1) offset which goes past the end of the section name string table
+## BROKEN-SECNAME: error: '[[FILE]]': a section [index 1] has an invalid sh_name (0x1) offset which goes past the end of the section name string table
--- !ELF
FileHeader:
## Check we do not fail to dump the section headers when
## a .shstrtab section does not have a SHT_STRTAB type.
+## Check we report only one warning for the issue for each input object.
+
# 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 -DFILE=%t1 --implicit-check-not warning --check-prefix LLVM
+# RUN: llvm-readelf -S %t1 2>&1 | FileCheck %s -DFILE=%t1 --implicit-check-not warning --check-prefix GNU
+
+# LLVM: warning: '[[FILE]]': 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: Section Headers:
+# GNU: [Nr] Name Type Address Off Size ES Flg Lk Inf Al
+# GNU: warning: '[[FILE]]': 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
+
+## Test we report multiple identical warnings (one for each object) when dumping an archive.
+
+# RUN: rm -f %t.a
+# RUN: cp %t1 %t2
+# RUN: llvm-ar rc %t.a %t1 %t2 %t1
+# RUN: llvm-readobj -S %t.a 2>&1 | FileCheck %s --implicit-check-not warning --check-prefix WARNINGS
+# RUN: llvm-readelf -S %t.a 2>&1 | FileCheck %s --implicit-check-not warning --check-prefix WARNINGS
+
+# WARNINGS: warning: '{{.*}}1': invalid sh_type for string table section [index 1]: expected SHT_STRTAB, but got SHT_PROGBITS
+# WARNINGS: warning: '{{.*}}2': invalid sh_type for string table section [index 1]: expected SHT_STRTAB, but got SHT_PROGBITS
+# WARNINGS: warning: '{{.*}}1': invalid sh_type for string table section [index 1]: expected SHT_STRTAB, but got SHT_PROGBITS
-# LLVM: Name: .shstrtab
-# LLVM-NEXT: Type: SHT_PROGBITS
+## Test we report the warning for each input file specified on the command line.
-# GNU: [Nr] Name Type
-# GNU: [ 1] .shstrtab PROGBITS
+# RUN: llvm-readobj -S %t1 %t2 %t1 2>&1 | FileCheck %s --implicit-check-not warning --check-prefix WARNINGS
+# RUN: llvm-readelf -S %t1 %t2 %t1 2>&1 | FileCheck %s --implicit-check-not warning --check-prefix WARNINGS
--- !ELF
FileHeader:
#include <memory>
#include <string>
#include <system_error>
+#include <unordered_set>
#include <vector>
using namespace llvm;
using Elf_Sym = typename ELFT::Sym;
using Elf_Addr = typename ELFT::Addr;
- DumpStyle(ELFDumper<ELFT> *Dumper) : Dumper(Dumper) {}
+ DumpStyle(ELFDumper<ELFT> *Dumper) : Dumper(Dumper) {
+ // Dumper reports all non-critical errors as warnings.
+ // It does not print the same warning more than once.
+ WarningHandler = [this](const Twine &Msg) {
+ StringRef FileName = this->Dumper->getElfObject()->getFileName();
+ if (Warnings.insert(Msg.str()).second)
+ reportWarning(FileName, createError(Msg));
+ return Error::success();
+ };
+ }
+
virtual ~DumpStyle() = default;
virtual void printFileHeaders(const ELFFile<ELFT> *Obj) = 0;
virtual void printMipsPLT(const MipsGOTParser<ELFT> &Parser) = 0;
const ELFDumper<ELFT> *dumper() const { return Dumper; }
+protected:
+ std::function<Error(const Twine &Msg)> WarningHandler;
+
private:
+ std::unordered_set<std::string> Warnings;
const ELFDumper<ELFT> *Dumper;
};
return "";
}
-template <class ELFT>
-static StringRef getSectionName(const typename ELFT::Shdr &Sec,
- const ELFObjectFile<ELFT> &ElfObj,
- ArrayRef<typename ELFT::Shdr> Sections) {
- const ELFFile<ELFT> &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<uint8_t>(&Sections[Index])));
- return unwrapOrError(Obj.getSectionName(&Sec, Data));
-}
-
template <class ELFT>
void GNUStyle<ELFT>::printSectionHeaders(const ELFO *Obj) {
unsigned Bias = ELFT::Is64Bits ? 0 : 8;
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<StringRef>(
+ ElfObj->getFileName(), Obj->getSectionName(&Sec, this->WarningHandler));
Fields[2].Str =
getSectionTypeString(Obj->getHeader()->e_machine, Sec.sh_type);
Fields[3].Str =
ArrayRef<Elf_Shdr> Sections = unwrapOrError(Obj->sections());
const ELFObjectFile<ELFT> *ElfObj = this->dumper()->getElfObject();
for (const Elf_Shdr &Sec : Sections) {
- StringRef Name = getSectionName(Sec, *ElfObj, Sections);
+ StringRef Name = unwrapOrError(
+ ElfObj->getFileName(), Obj->getSectionName(&Sec, this->WarningHandler));
DictScope SectionD(W, "Section");
W.printNumber("Index", ++SectionIndex);
W.printNumber("Name", Name, Sec.sh_name);
WithColor::warning(errs()) << Msg << "\n";
}
+void reportWarning(StringRef Input, Error Err) {
+ if (Input == "-")
+ Input = "<stdin>";
+ warn(createFileError(Input, std::move(Err)));
+}
+
void warn(Error Err) {
handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) {
reportWarning(EI.message());
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg);
void reportError(StringRef Input, Error Err);
void reportWarning(Twine Msg);
+ void reportWarning(StringRef Input, Error Err);
void warn(llvm::Error Err);
void error(std::error_code EC);
void error(llvm::Error EC);
return *EO;
reportError(EO.getError().message());
}
+
+ // TODO: This one is deprecated. Use one with a Input name below.
template <class T> T unwrapOrError(Expected<T> EO) {
if (EO)
return *EO;
OS.flush();
reportError(Buf);
}
+
+ template <class T> T unwrapOrError(StringRef Input, Expected<T> EO) {
+ if (EO)
+ return *EO;
+ reportError(Input, EO.takeError());
+ llvm_unreachable("reportError shouldn't return in this case");
+ }
} // namespace llvm
namespace opts {