diff --git a/llvm/include/llvm/Object/Binary.h b/llvm/include/llvm/Object/Binary.h --- a/llvm/include/llvm/Object/Binary.h +++ b/llvm/include/llvm/Object/Binary.h @@ -91,6 +91,8 @@ Binary(const Binary &other) = delete; virtual ~Binary(); + virtual Error initContent() { return Error::success(); }; + StringRef getData() const; StringRef getFileName() const; MemoryBufferRef getMemoryBufferRef() const; @@ -178,7 +180,8 @@ /// /// @param Source The data to create the Binary from. Expected> createBinary(MemoryBufferRef Source, - LLVMContext *Context = nullptr); + LLVMContext *Context = nullptr, + bool InitContent = true); template class OwningBinary { std::unique_ptr Bin; @@ -229,7 +232,8 @@ } Expected> createBinary(StringRef Path, - LLVMContext *Context = nullptr); + LLVMContext *Context = nullptr, + bool InitContent = true); } // end namespace object 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 @@ -246,11 +246,15 @@ return SectionRef(toDRI(Sec), this); } + bool IsContentValid() const { return ContentValid; } + private: ELFObjectFile(MemoryBufferRef Object, ELFFile EF, const Elf_Shdr *DotDynSymSec, const Elf_Shdr *DotSymtabSec, const Elf_Shdr *DotSymtabShndxSec); + bool ContentValid = false; + protected: ELFFile EF; @@ -258,6 +262,8 @@ const Elf_Shdr *DotSymtabSec = nullptr; // Symbol table section. const Elf_Shdr *DotSymtabShndxSec = nullptr; // SHT_SYMTAB_SHNDX section. + Error initContent() override; + void moveSymbolNext(DataRefImpl &Symb) const override; Expected getSymbolName(DataRefImpl Symb) const override; Expected getSymbolAddress(DataRefImpl Symb) const override; @@ -400,7 +406,8 @@ public: ELFObjectFile(ELFObjectFile &&Other); - static Expected> create(MemoryBufferRef Object); + static Expected> create(MemoryBufferRef Object, + bool InitContent = true); const Elf_Rel *getRel(DataRefImpl Rel) const; const Elf_Rela *getRela(DataRefImpl Rela) const; @@ -457,6 +464,35 @@ ++Sym.d.b; } +template Error ELFObjectFile::initContent() { + auto SectionsOrErr = EF.sections(); + if (!SectionsOrErr) + return SectionsOrErr.takeError(); + + for (const Elf_Shdr &Sec : *SectionsOrErr) { + switch (Sec.sh_type) { + case ELF::SHT_DYNSYM: { + if (!DotDynSymSec) + DotDynSymSec = &Sec; + break; + } + case ELF::SHT_SYMTAB: { + if (!DotSymtabSec) + DotSymtabSec = &Sec; + break; + } + case ELF::SHT_SYMTAB_SHNDX: { + if (!DotSymtabShndxSec) + DotSymtabShndxSec = &Sec; + break; + } + } + } + + ContentValid = true; + return Error::success(); +} + template Expected ELFObjectFile::getSymbolName(DataRefImpl Sym) const { const Elf_Sym *ESym = getSymbol(Sym); @@ -992,40 +1028,17 @@ template Expected> -ELFObjectFile::create(MemoryBufferRef Object) { +ELFObjectFile::create(MemoryBufferRef Object, bool InitContent) { auto EFOrErr = ELFFile::create(Object.getBuffer()); if (Error E = EFOrErr.takeError()) return std::move(E); - auto EF = std::move(*EFOrErr); - - auto SectionsOrErr = EF.sections(); - if (!SectionsOrErr) - return SectionsOrErr.takeError(); - const Elf_Shdr *DotDynSymSec = nullptr; - const Elf_Shdr *DotSymtabSec = nullptr; - const Elf_Shdr *DotSymtabShndxSec = nullptr; - for (const Elf_Shdr &Sec : *SectionsOrErr) { - switch (Sec.sh_type) { - case ELF::SHT_DYNSYM: { - if (!DotDynSymSec) - DotDynSymSec = &Sec; - break; - } - case ELF::SHT_SYMTAB: { - if (!DotSymtabSec) - DotSymtabSec = &Sec; - break; - } - case ELF::SHT_SYMTAB_SHNDX: { - if (!DotSymtabShndxSec) - DotSymtabShndxSec = &Sec; - break; - } - } - } - return ELFObjectFile(Object, EF, DotDynSymSec, DotSymtabSec, - DotSymtabShndxSec); + ELFObjectFile Obj = {Object, std::move(*EFOrErr), nullptr, nullptr, + nullptr}; + if (InitContent) + if (Error E = Obj.initContent()) + return std::move(E); + return Obj; } template diff --git a/llvm/include/llvm/Object/ObjectFile.h b/llvm/include/llvm/Object/ObjectFile.h --- a/llvm/include/llvm/Object/ObjectFile.h +++ b/llvm/include/llvm/Object/ObjectFile.h @@ -350,7 +350,8 @@ createObjectFile(StringRef ObjectPath); static Expected> - createObjectFile(MemoryBufferRef Object, llvm::file_magic Type); + createObjectFile(MemoryBufferRef Object, llvm::file_magic Type, + bool InitContent = true); static Expected> createObjectFile(MemoryBufferRef Object) { return createObjectFile(Object, llvm::file_magic::unknown); @@ -367,7 +368,7 @@ createXCOFFObjectFile(MemoryBufferRef Object, unsigned FileType); static Expected> - createELFObjectFile(MemoryBufferRef Object); + createELFObjectFile(MemoryBufferRef Object, bool InitContent = true); static Expected> createMachOObjectFile(MemoryBufferRef Object, diff --git a/llvm/include/llvm/Object/SymbolicFile.h b/llvm/include/llvm/Object/SymbolicFile.h --- a/llvm/include/llvm/Object/SymbolicFile.h +++ b/llvm/include/llvm/Object/SymbolicFile.h @@ -161,14 +161,12 @@ // construction aux. static Expected> createSymbolicFile(MemoryBufferRef Object, llvm::file_magic Type, - LLVMContext *Context); + LLVMContext *Context, bool InitContent = true); static Expected> createSymbolicFile(MemoryBufferRef Object) { return createSymbolicFile(Object, llvm::file_magic::unknown, nullptr); } - static Expected> - createSymbolicFile(StringRef ObjectPath); static bool classof(const Binary *v) { return v->isSymbolic(); diff --git a/llvm/lib/Object/Binary.cpp b/llvm/lib/Object/Binary.cpp --- a/llvm/lib/Object/Binary.cpp +++ b/llvm/lib/Object/Binary.cpp @@ -44,7 +44,8 @@ MemoryBufferRef Binary::getMemoryBufferRef() const { return Data; } Expected> object::createBinary(MemoryBufferRef Buffer, - LLVMContext *Context) { + LLVMContext *Context, + bool InitContent) { file_magic Type = identify_magic(Buffer.getBuffer()); switch (Type) { @@ -73,7 +74,7 @@ case file_magic::xcoff_object_32: case file_magic::xcoff_object_64: case file_magic::wasm_object: - return ObjectFile::createSymbolicFile(Buffer, Type, Context); + return ObjectFile::createSymbolicFile(Buffer, Type, Context, InitContent); case file_magic::macho_universal_binary: return MachOUniversalBinary::create(Buffer); case file_magic::windows_resource: @@ -93,8 +94,8 @@ llvm_unreachable("Unexpected Binary File Type"); } -Expected> object::createBinary(StringRef Path, - LLVMContext *Context) { +Expected> +object::createBinary(StringRef Path, LLVMContext *Context, bool InitContent) { ErrorOr> FileOrErr = MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1, /*RequiresNullTerminator=*/false); @@ -103,7 +104,7 @@ std::unique_ptr &Buffer = FileOrErr.get(); Expected> BinOrErr = - createBinary(Buffer->getMemBufferRef(), Context); + createBinary(Buffer->getMemBufferRef(), Context, InitContent); if (!BinOrErr) return BinOrErr.takeError(); std::unique_ptr &Bin = BinOrErr.get(); diff --git a/llvm/lib/Object/ELFObjectFile.cpp b/llvm/lib/Object/ELFObjectFile.cpp --- a/llvm/lib/Object/ELFObjectFile.cpp +++ b/llvm/lib/Object/ELFObjectFile.cpp @@ -61,15 +61,15 @@ template static Expected>> -createPtr(MemoryBufferRef Object) { - auto Ret = ELFObjectFile::create(Object); +createPtr(MemoryBufferRef Object, bool InitContent) { + auto Ret = ELFObjectFile::create(Object, InitContent); if (Error E = Ret.takeError()) return std::move(E); return std::make_unique>(std::move(*Ret)); } Expected> -ObjectFile::createELFObjectFile(MemoryBufferRef Obj) { +ObjectFile::createELFObjectFile(MemoryBufferRef Obj, bool InitContent) { std::pair Ident = getElfArchType(Obj.getBuffer()); std::size_t MaxAlignment = @@ -80,16 +80,16 @@ if (Ident.first == ELF::ELFCLASS32) { if (Ident.second == ELF::ELFDATA2LSB) - return createPtr(Obj); + return createPtr(Obj, InitContent); else if (Ident.second == ELF::ELFDATA2MSB) - return createPtr(Obj); + return createPtr(Obj, InitContent); else return createError("Invalid ELF data"); } else if (Ident.first == ELF::ELFCLASS64) { if (Ident.second == ELF::ELFDATA2LSB) - return createPtr(Obj); + return createPtr(Obj, InitContent); else if (Ident.second == ELF::ELFDATA2MSB) - return createPtr(Obj); + return createPtr(Obj, InitContent); else return createError("Invalid ELF data"); } diff --git a/llvm/lib/Object/ObjectFile.cpp b/llvm/lib/Object/ObjectFile.cpp --- a/llvm/lib/Object/ObjectFile.cpp +++ b/llvm/lib/Object/ObjectFile.cpp @@ -132,7 +132,8 @@ } Expected> -ObjectFile::createObjectFile(MemoryBufferRef Object, file_magic Type) { +ObjectFile::createObjectFile(MemoryBufferRef Object, file_magic Type, + bool InitContent) { StringRef Data = Object.getBuffer(); if (Type == file_magic::unknown) Type = identify_magic(Data); @@ -154,7 +155,7 @@ case file_magic::elf_executable: case file_magic::elf_shared_object: case file_magic::elf_core: - return createELFObjectFile(Object); + return createELFObjectFile(Object, InitContent); case file_magic::macho_object: case file_magic::macho_executable: case file_magic::macho_fixed_virtual_memory_shared_lib: diff --git a/llvm/lib/Object/SymbolicFile.cpp b/llvm/lib/Object/SymbolicFile.cpp --- a/llvm/lib/Object/SymbolicFile.cpp +++ b/llvm/lib/Object/SymbolicFile.cpp @@ -36,7 +36,7 @@ Expected> SymbolicFile::createSymbolicFile(MemoryBufferRef Object, file_magic Type, - LLVMContext *Context) { + LLVMContext *Context, bool InitContent) { StringRef Data = Object.getBuffer(); if (Type == file_magic::unknown) Type = identify_magic(Data); @@ -67,14 +67,14 @@ case file_magic::xcoff_object_32: case file_magic::xcoff_object_64: case file_magic::wasm_object: - return ObjectFile::createObjectFile(Object, Type); + return ObjectFile::createObjectFile(Object, Type, InitContent); case file_magic::coff_import_library: return std::unique_ptr(new COFFImportFile(Object)); case file_magic::elf_relocatable: case file_magic::macho_object: case file_magic::coff_object: { Expected> Obj = - ObjectFile::createObjectFile(Object, Type); + ObjectFile::createObjectFile(Object, Type, InitContent); if (!Obj || !Context) return std::move(Obj); 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 @@ -175,9 +175,11 @@ ## when the e_shentsize field is broken. # RUN: yaml2obj %s --docnum=9 -o %t9 -# RUN: not llvm-readobj -S %t9 2>&1 | FileCheck --check-prefix=INVALID-SH-ENTSIZE %s +# RUN: not llvm-readobj -S %t9 2>&1 | \ +# RUN: FileCheck -DFILE=%t9 --implicit-check-not=warning: --check-prefix=INVALID-SH-ENTSIZE %s -# INVALID-SH-ENTSIZE: error: {{.*}}: invalid e_shentsize in ELF header: 1 +# INVALID-SH-ENTSIZE: LoadName: +# INVALID-SH-ENTSIZE-NEXT: error: '[[FILE]]': unable to continue dumping, the file is corrupt: invalid e_shentsize in ELF header: 1 --- !ELF FileHeader: @@ -312,10 +314,12 @@ ## when the e_shnum field is broken (is greater than the actual number of sections). # RUN: yaml2obj %s --docnum=15 -o %t15 -# RUN: not llvm-readobj -S %t15 2>&1 | FileCheck --check-prefix=INVALID-SECTION-NUM %s +# RUN: not llvm-readobj -S %t15 2>&1 | \ +# RUN: FileCheck -DFILE=%t15 --implicit-check-not=warning: --check-prefix=INVALID-SECTION-NUM %s + +# INVALID-SECTION-NUM: LoadName: +# INVALID-SECTION-NUM-NEXT: error: '[[FILE]]': unable to continue dumping, the file is corrupt: section table goes past the end of file -# INVALID-SECTION-NUM: error: {{.*}}: section table goes past the end of file - --- !ELF FileHeader: Class: ELFCLASS64 @@ -551,7 +555,7 @@ # RUN: yaml2obj --docnum=25 %s -o %t25 # RUN: not llvm-readobj -h %t25 2>&1 | FileCheck -DFILE=%t25 --check-prefix=INVALID-SEC-NUM1 %s -# INVALID-SEC-NUM1: error: '[[FILE]]': invalid section header table offset (e_shoff = 0x58) or invalid number of sections specified in the first section header's sh_size field (0x3ffffffffffffff) +# INVALID-SEC-NUM1: error: '[[FILE]]': unable to continue dumping, the file is corrupt: invalid section header table offset (e_shoff = 0x58) or invalid number of sections specified in the first section header's sh_size field (0x3ffffffffffffff) --- !ELF FileHeader: @@ -570,7 +574,7 @@ # RUN: yaml2obj --docnum=26 %s -o %t26 # RUN: not llvm-readobj -h %t26 2>&1 | FileCheck -DFILE=%t26 --check-prefix=INVALID-SEC-NUM2 %s -# INVALID-SEC-NUM2: error: '[[FILE]]': invalid number of sections specified in the NULL section's sh_size field (288230376151711744) +# INVALID-SEC-NUM2: error: '[[FILE]]': unable to continue dumping, the file is corrupt: invalid number of sections specified in the NULL section's sh_size field (288230376151711744) --- !ELF FileHeader: @@ -588,8 +592,8 @@ # RUN: yaml2obj --docnum=27 %s -o %t27 # RUN: not llvm-readobj -h %t27 2>&1 | FileCheck -DFILE=%t27 --check-prefix=INVALID-SEC-NUM3 %s -# INVALID-SEC-NUM3: error: '[[FILE]]': section header table goes past the end of the file: e_shoff = 0xffffffffffffffff - +# INVALID-SEC-NUM3: error: '[[FILE]]': unable to continue dumping, the file is corrupt: section header table goes past the end of the file: e_shoff = 0xffffffffffffffff + --- !ELF FileHeader: Class: ELFCLASS64 diff --git a/llvm/test/tools/llvm-readobj/ELF/file-headers.test b/llvm/test/tools/llvm-readobj/ELF/file-headers.test --- a/llvm/test/tools/llvm-readobj/ELF/file-headers.test +++ b/llvm/test/tools/llvm-readobj/ELF/file-headers.test @@ -137,3 +137,98 @@ # LANAI-NEXT: StringTableSectionIndex: 2 # LANAI-NEXT:} # LANAI-NOT:{{.}} + +## Check we are able to dump the file header when the section header table can't be read. + +# RUN: yaml2obj %s --docnum=4 -o %t.invalid1 +# RUN: not llvm-readobj --file-headers %t.invalid1 2>&1 \ +# RUN: | FileCheck %s --implicit-check-not=warning: -DFILE=%t.invalid1 \ +# RUN: -DSECHDRCOUNT=8192 -DSECHDRSTRTABINDEX=12288 --check-prefix=INVALID-LLVM +# RUN: not llvm-readelf --file-headers %t.invalid1 2>&1 \ +# RUN: | FileCheck %s --implicit-check-not=warning: -DFILE=%t.invalid1 \ +# RUN: -DSECHDRCOUNT=8192 -DSECHDRSTRTABINDEX=12288 --check-prefix=INVALID-GNU + +# INVALID-LLVM: File: [[FILE]] +# INVALID-LLVM-NEXT: Format: elf64-unknown +# INVALID-LLVM-NEXT: Arch: unknown +# INVALID-LLVM-NEXT: AddressSize: 64bit +# INVALID-LLVM-NEXT: LoadName: +# INVALID-LLVM-NEXT: ElfHeader { +# INVALID-LLVM-NEXT: Ident { +# INVALID-LLVM-NEXT: Magic: (7F 45 4C 46) +# INVALID-LLVM-NEXT: Class: 64-bit (0x2) +# INVALID-LLVM-NEXT: DataEncoding: LittleEndian (0x1) +# INVALID-LLVM-NEXT: FileVersion: 1 +# INVALID-LLVM-NEXT: OS/ABI: SystemV (0x0) +# INVALID-LLVM-NEXT: ABIVersion: 0 +# INVALID-LLVM-NEXT: Unused: (00 00 00 00 00 00 00) +# INVALID-LLVM-NEXT: } +# INVALID-LLVM-NEXT: Type: Relocatable (0x1) +# INVALID-LLVM-NEXT: Machine: EM_NONE (0x0) +# INVALID-LLVM-NEXT: Version: 1 +# INVALID-LLVM-NEXT: Entry: 0x0 +# INVALID-LLVM-NEXT: ProgramHeaderOffset: 0x0 +# INVALID-LLVM-NEXT: SectionHeaderOffset: 0x1000 +# INVALID-LLVM-NEXT: Flags [ (0x0) +# INVALID-LLVM-NEXT: ] +# INVALID-LLVM-NEXT: HeaderSize: 64 +# INVALID-LLVM-NEXT: ProgramHeaderEntrySize: 0 +# INVALID-LLVM-NEXT: ProgramHeaderCount: 0 +# INVALID-LLVM-NEXT: SectionHeaderEntrySize: 64 +# INVALID-LLVM-NEXT: SectionHeaderCount: [[SECHDRCOUNT]] +# INVALID-LLVM-NEXT: StringTableSectionIndex: [[SECHDRSTRTABINDEX]] +# INVALID-LLVM-NEXT: } +# INVALID-LLVM-NEXT: error: '[[FILE]]': unable to continue dumping, the file is corrupt: section header table goes past the end of the file: e_shoff = 0x1000 + +# INVALID-GNU: ELF Header: +# INVALID-GNU-NEXT: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 +# INVALID-GNU-NEXT: Class: ELF64 +# INVALID-GNU-NEXT: Data: 2's complement, little endian +# INVALID-GNU-NEXT: Version: 1 (current) +# INVALID-GNU-NEXT: OS/ABI: UNIX - System V +# INVALID-GNU-NEXT: ABI Version: 0 +# INVALID-GNU-NEXT: Type: REL (Relocatable file) +# INVALID-GNU-NEXT: Machine: None +# INVALID-GNU-NEXT: Version: 0x1 +# INVALID-GNU-NEXT: Entry point address: 0x0 +# INVALID-GNU-NEXT: Start of program headers: 0 (bytes into file) +# INVALID-GNU-NEXT: Start of section headers: 4096 (bytes into file) +# INVALID-GNU-NEXT: Flags: 0x0 +# INVALID-GNU-NEXT: Size of this header: 64 (bytes) +# INVALID-GNU-NEXT: Size of program headers: 0 (bytes) +# INVALID-GNU-NEXT: Number of program headers: 0 +# INVALID-GNU-NEXT: Size of section headers: 64 (bytes) +# INVALID-GNU-NEXT: Number of section headers: [[SECHDRCOUNT]] +# INVALID-GNU-NEXT: Section header string table index: [[SECHDRSTRTABINDEX]] +# INVALID-GNU-NEXT: error: '[[FILE]]': unable to continue dumping, the file is corrupt: section header table goes past the end of the file: e_shoff = 0x1000 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL +## The section header table offset goes past the EOF. + EShOff: 0x1000 +## The number of section headers is too large, the file is +## too little to contain so many sections. + EShNum: [[SHNUM=0x2000]] +## The index of the section name string table is too large. +## The section would be past the EOF. + EShStrNdx: [[SHSTRNDX=0x3000]] +SectionHeaderTable: + NoHeaders: true + +## Check we don't dump anything except the file header when the section header table can't be read. + +# RUN: not llvm-readobj -a %t.invalid 2>&1 \ +# RUN: | FileCheck %s -DFILE=%t.invalid -DSECHDRCOUNT=8192 -DSECHDRSTRTABINDEX=12288 --check-prefix=INVALID-LLVM +# RUN: not llvm-readelf -a %t.invalid 2>&1 \ +# RUN: | FileCheck %s -DFILE=%t.invalid -DSECHDRCOUNT=8192 -DSECHDRSTRTABINDEX=12288 --check-prefix=INVALID-GNU + +## Check what we print when e_shnum == 0, e_shstrndx == SHN_XINDEX and the section header table can't be read. + +# RUN: yaml2obj %s -DSHNUM=0 -DSHSTRNDX=0xffff --docnum=4 -o %t.invalid2 +# RUN: not llvm-readobj --file-headers %t.invalid2 2>&1 \ +# RUN: | FileCheck %s -DFILE=%t.invalid2 -DSECHDRCOUNT="" -DSECHDRSTRTABINDEX="" --check-prefix=INVALID-LLVM +# RUN: not llvm-readelf --file-headers %t.invalid2 2>&1 \ +# RUN: | FileCheck %s -DFILE=%t.invalid2 -DSECHDRCOUNT="" -DSECHDRSTRTABINDEX="" --check-prefix=INVALID-GNU diff --git a/llvm/test/tools/yaml2obj/ELF/section-headers.yaml b/llvm/test/tools/yaml2obj/ELF/section-headers.yaml --- a/llvm/test/tools/yaml2obj/ELF/section-headers.yaml +++ b/llvm/test/tools/yaml2obj/ELF/section-headers.yaml @@ -174,7 +174,7 @@ ## Test that we are still able to override e_shoff, e_shnum and e_shstrndx ## fields even when we do not produce section headers. # RUN: yaml2obj %s --docnum=6 -o %t4 -# RUN: llvm-readelf --file-headers %t4 | FileCheck %s --check-prefix=NO-HEADERS-OVERRIDE +# RUN: not llvm-readelf --file-headers %t4 | FileCheck %s --check-prefix=NO-HEADERS-OVERRIDE # NO-HEADERS-OVERRIDE: Start of section headers: 2 (bytes into file) # NO-HEADERS-OVERRIDE: Number of section headers: 3 @@ -188,13 +188,6 @@ EShOff: 0x2 EShNum: 0x3 EShStrNdx: 0x4 -Sections: - - Name: .foo - Type: SHT_PROGBITS -## FIXME: we have to set an arbitrary size to create a -## piece of dummy data to make llvm-readelf happy. -## See: https://bugs.llvm.org/show_bug.cgi?id=40804 - Size: 0x100 SectionHeaderTable: NoHeaders: true 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 @@ -1998,6 +1998,9 @@ else ELFDumperStyle.reset(new LLVMStyle(Writer, *this)); + if (!O.IsContentValid()) + return; + typename ELFT::ShdrRange Sections = cantFail(Obj.sections()); for (const Elf_Shdr &Sec : Sections) { switch (Sec.sh_type) { @@ -3447,10 +3450,17 @@ if (ElfHeader.e_shnum != 0) return to_string(ElfHeader.e_shnum); - ArrayRef Arr = cantFail(Obj.sections()); - if (Arr.empty()) + Expected> ArrOrErr = Obj.sections(); + if (!ArrOrErr) { + // In this case we can ignore an error, because we have already reported a + // warning about the broken section header table earlier. + consumeError(ArrOrErr.takeError()); + return ""; + } + + if (ArrOrErr->empty()) return "0"; - return "0 (" + to_string(Arr[0].sh_size) + ")"; + return "0 (" + to_string((*ArrOrErr)[0].sh_size) + ")"; } template @@ -3460,11 +3470,18 @@ if (ElfHeader.e_shstrndx != SHN_XINDEX) return to_string(ElfHeader.e_shstrndx); - ArrayRef Arr = cantFail(Obj.sections()); - if (Arr.empty()) + Expected> ArrOrErr = Obj.sections(); + if (!ArrOrErr) { + // In this case we can ignore an error, because we have already reported a + // warning about the broken section header table earlier. + consumeError(ArrOrErr.takeError()); + return ""; + } + + if (ArrOrErr->empty()) return "65535 (corrupt: out of range)"; - return to_string(ElfHeader.e_shstrndx) + " (" + to_string(Arr[0].sh_link) + - ")"; + return to_string(ElfHeader.e_shstrndx) + " (" + + to_string((*ArrOrErr)[0].sh_link) + ")"; } template void GNUStyle::printFileHeaders() { diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h --- a/llvm/tools/llvm-readobj/ObjDumper.h +++ b/llvm/tools/llvm-readobj/ObjDumper.h @@ -35,6 +35,8 @@ ObjDumper(ScopedPrinter &Writer); virtual ~ObjDumper(); + virtual bool canDumpContent() { return true; } + virtual void printFileHeaders() = 0; virtual void printSectionHeaders() = 0; virtual void printRelocations() = 0; diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp --- a/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -458,12 +458,17 @@ } /// Dumps the specified object file. -static void dumpObject(const ObjectFile &Obj, ScopedPrinter &Writer, +static void dumpObject(ObjectFile &Obj, ScopedPrinter &Writer, const Archive *A = nullptr) { std::string FileStr = A ? Twine(A->getFileName() + "(" + Obj.getFileName() + ")").str() : Obj.getFileName().str(); + std::string ContentErrString; + if (Error ContentErr = Obj.initContent()) + ContentErrString = "unable to continue dumping, the file is corrupt: " + + toString(std::move(ContentErr)); + ObjDumper *Dumper; Expected> DumperOrErr = createDumper(Obj, Writer); if (!DumperOrErr) @@ -486,6 +491,11 @@ if (opts::FileHeaders) Dumper->printFileHeaders(); + // This is only used for ELF currently. In some cases, when an object is + // corrupt (e.g. truncated), we can't dump anything except the file header. + if (!ContentErrString.empty()) + reportError(createError(ContentErrString), FileStr); + if (opts::SectionDetails || opts::SectionHeaders) { if (opts::Output == opts::GNU && opts::SectionDetails) Dumper->printSectionDetails(); @@ -637,7 +647,8 @@ /// Opens \a File and dumps it. static void dumpInput(StringRef File, ScopedPrinter &Writer) { // Attempt to open the binary. - Expected> BinaryOrErr = createBinary(File); + Expected> BinaryOrErr = + createBinary(File, /*Context=*/nullptr, /*InitContent=*/false); if (!BinaryOrErr) reportError(BinaryOrErr.takeError(), File); Binary &Binary = *BinaryOrErr.get().getBinary();