llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-llvm-binary-utilities Author: None (aokblast) <details> <summary>Changes</summary> FreeBSD coredump uses program headers to store mmap information. It is possible for program to use more than PN_XNUM mmaps. Therefore, we implement the support of PN_XNUM in readelf. --- Full diff: https://github.com/llvm/llvm-project/pull/165278.diff 4 Files Affected: - (added) llvm/test/tools/llvm-readobj/ELF/Inputs/many-segments.o.gz () - (added) llvm/test/tools/llvm-readobj/ELF/invalid-e_phnum.test (+39) - (added) llvm/test/tools/llvm-readobj/ELF/many-segments.test (+79) - (modified) llvm/tools/llvm-readobj/ELFDumper.cpp (+50-22) ``````````diff diff --git a/llvm/test/tools/llvm-readobj/ELF/Inputs/many-segments.o.gz b/llvm/test/tools/llvm-readobj/ELF/Inputs/many-segments.o.gz new file mode 100644 index 0000000000000..0709ed1d6389e Binary files /dev/null and b/llvm/test/tools/llvm-readobj/ELF/Inputs/many-segments.o.gz differ diff --git a/llvm/test/tools/llvm-readobj/ELF/invalid-e_phnum.test b/llvm/test/tools/llvm-readobj/ELF/invalid-e_phnum.test new file mode 100644 index 0000000000000..a174742af7192 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/invalid-e_phnum.test @@ -0,0 +1,39 @@ +# RUN: yaml2obj --docnum=1 %s -o %t.o + +# RUN: llvm-readobj --headers %t.o 2>&1 | FileCheck %s --check-prefix=CASE-INVALID + +# CASE-INVALID: SectionHeaderOffset: 0 +# CASE-INVALID: ProgramHeaderCount: 65535 (corrupt) +# CASE-INVALID: unable to dump program headers: program headers are longer than binary of size 336: e_phoff = 0x40, e_phnum = 65535, e_phentsize = 56 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 + EPhNum: 65535 + EShOff: 0 +ProgramHeaders: + - Type: PT_LOAD + +# RUN: yaml2obj --docnum=2 %s -o %t2.o + +# RUN: llvm-readobj --headers %t2.o 2>&1 | FileCheck %s --check-prefix=CASE-VALID + +# CASE-VALID: SectionHeaderOffset: 0 +# CASE-VALID: ProgramHeaderCount: 65535 (65536) +# CASE-VALID: unable to dump program headers: program headers are longer than binary of size 336: e_phoff = 0x40, e_phnum = 65536, e_phentsize = 56 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 + EPhNum: 65535 +Sections: + - Type: SHT_NULL + Info: 65536 +ProgramHeaders: + - Type: PT_LOAD diff --git a/llvm/test/tools/llvm-readobj/ELF/many-segments.test b/llvm/test/tools/llvm-readobj/ELF/many-segments.test new file mode 100644 index 0000000000000..2f154ddf53899 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/many-segments.test @@ -0,0 +1,79 @@ +## Show that llvm-readelf can handle an input file with many segments. + +RUN: %python %p/../../llvm-objcopy/Inputs/ungzip.py %p/Inputs/many-segments.o.gz > %t +RUN: llvm-readobj --file-headers --sections --segments %t | FileCheck %s +RUN: llvm-readelf --segments %t | FileCheck --check-prefix=SYMS %s + +## The ELF header should have e_phnum == PN_XNUM +# CHECK: ProgramHeaderCount: 65535 (66549) +## The first section header should store the real program header count in its fields. +# CHECK: Section { +# CHECK-NEXT: Index: 0 +# CHECK-NEXT: Name: +# CHECK-NEXT: Type: SHT_NULL +# CHECK-NEXT: Flags [ +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: +# CHECK-NEXT: Link: +# CHECK-NEXT: Info: 66549 + +## Show that the symbols with segments indexes around the reserved range still +## have the right segment indexes afterwards. +# 65535th segment +# CHECK: Offset: 0x1183B000 +# CHECK-NEXT: VirtualAddress: 0x349139F3000 +# CHECK: } +# CHECK-NEXT ProgramHeader { +# CHECK-NEXT Type: PT_LOAD (0x1) +# CHECK-NEXT Offset: 0x1183C000 +# CHECK-NEXT VirtualAddress: 0x349139F4000 +# CHECK-NEXT PhysicalAddress: 0x0 +# CHECK-NEXT FileSize: 4096 +# CHECK-NEXT MemSize: 4096 +# CHECK-NEXT Flags [ (0x4) +# CHECK-NEXT PF_R (0x4) +# CHECK-NEXT ] +# CHECK-NEXT Alignment: 4096 +# CHECK-NEXT } +# CHECK-NEXT ProgramHeader { +# CHECK-NEXT Type: PT_LOAD (0x1) +# CHECK-NEXT Offset: 0x1183D000 +# CHECK-NEXT VirtualAddress: 0x349139F5000 +# CHECK-NEXT PhysicalAddress: 0x0 +# CHECK-NEXT FileSize: 4096 +# CHECK-NEXT MemSize: 4096 +# CHECK-NEXT Flags [ (0x6) +# CHECK-NEXT PF_R (0x4) +# CHECK-NEXT PF_W (0x2) +# CHECK-NEXT ] +# CHECK-NEXT Alignment: 4096 +# CHECK-NEXT } +# CHECK-NEXT ProgramHeader { +# CHECK-NEXT Type: PT_LOAD (0x1) +# CHECK-NEXT Offset: 0x1183E000 +# CHECK-NEXT VirtualAddress: 0x349139F6000 +# CHECK-NEXT PhysicalAddress: 0x0 +# CHECK-NEXT FileSize: 4096 +# CHECK-NEXT MemSize: 4096 +# CHECK-NEXT Flags [ (0x4) +# CHECK-NEXT PF_R (0x4) +# CHECK-NEXT ] +# CHECK-NEXT Alignment: 4096 +# CHECK-NEXT } +# CHECK ProgramHeader { +# CHECK-NEXT Type: PT_LOAD (0x1) +# CHECK-NEXT Offset: 0x11C31000 +# CHECK-NEXT VirtualAddress: 0x30D8E7868000 +# CHECK-NEXT PhysicalAddress: 0x0 +# CHECK-NEXT FileSize: 8192 +# CHECK-NEXT MemSize: 8192 +# CHECK-NEXT Flags [ (0x6) +# CHECK-NEXT PF_R (0x4) +# CHECK-NEXT PF_W (0x2) +# CHECK-NEXT ] +# CHECK-NEXT Alignment: 4096 +# CHECK-NEXT } + +# SYMS: There are 66549 program headers, starting at offset 64 diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index 9c9b2dd79e686..22431c4396ca5 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -3572,45 +3572,62 @@ static inline void printFields(formatted_raw_ostream &OS, StringRef Str1, OS.flush(); } +template <class ELFT> +static std::string getProgramHeadersNumString(const ELFFile<ELFT> &Obj, + StringRef FileName) { + + if (Obj.getHeader().e_phnum != ELF::PN_XNUM) + return to_string(Obj.getHeader().e_phnum); + + Expected<uint32_t> PhNumOrErr = Obj.getPhNum(); + if (!PhNumOrErr) { + // In this case we can ignore an error, because we have already reported a + // warning about the broken section header table earlier. + consumeError(PhNumOrErr.takeError()); + return "<?>"; + } + + if (*PhNumOrErr == ELF::PN_XNUM) + return "65535 (corrupt)"; + return "65535 (" + to_string(*PhNumOrErr) + ")"; +} + template <class ELFT> static std::string getSectionHeadersNumString(const ELFFile<ELFT> &Obj, StringRef FileName) { - const typename ELFT::Ehdr &ElfHeader = Obj.getHeader(); - if (ElfHeader.e_shnum != 0) - return to_string(ElfHeader.e_shnum); + if (Obj.getHeader().e_shnum != 0) + return to_string(Obj.getHeader().e_shnum); - Expected<ArrayRef<typename ELFT::Shdr>> ArrOrErr = Obj.sections(); - if (!ArrOrErr) { + Expected<uint64_t> ShNumOrErr = Obj.getShNum(); + if (!ShNumOrErr) { // 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()); + consumeError(ShNumOrErr.takeError()); return "<?>"; } - if (ArrOrErr->empty()) + if (*ShNumOrErr == 0) return "0"; - return "0 (" + to_string((*ArrOrErr)[0].sh_size) + ")"; + return "0 (" + to_string(*ShNumOrErr) + ")"; } template <class ELFT> static std::string getSectionHeaderTableIndexString(const ELFFile<ELFT> &Obj, StringRef FileName) { - const typename ELFT::Ehdr &ElfHeader = Obj.getHeader(); - if (ElfHeader.e_shstrndx != SHN_XINDEX) - return to_string(ElfHeader.e_shstrndx); + if (Obj.getHeader().e_shstrndx != ELF::SHN_XINDEX) + return to_string(Obj.getHeader().e_shstrndx); - Expected<ArrayRef<typename ELFT::Shdr>> ArrOrErr = Obj.sections(); - if (!ArrOrErr) { + Expected<uint32_t> ShStrNdxOrErr = Obj.getShStrNdx(); + if (!ShStrNdxOrErr) { // 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()); + consumeError(ShStrNdxOrErr.takeError()); return "<?>"; } - if (ArrOrErr->empty()) + if (*ShStrNdxOrErr == ELF::SHN_XINDEX) return "65535 (corrupt: out of range)"; - return to_string(ElfHeader.e_shstrndx) + " (" + - to_string((*ArrOrErr)[0].sh_link) + ")"; + return "65535 (" + to_string(*ShStrNdxOrErr) + ")"; } static const EnumEntry<unsigned> *getObjectFileEnumEntry(unsigned Type) { @@ -3765,7 +3782,7 @@ template <class ELFT> void GNUELFDumper<ELFT>::printFileHeaders() { printFields(OS, "Size of this header:", Str); Str = to_string(e.e_phentsize) + " (bytes)"; printFields(OS, "Size of program headers:", Str); - Str = to_string(e.e_phnum); + Str = getProgramHeadersNumString(this->Obj, this->FileName); printFields(OS, "Number of program headers:", Str); Str = to_string(e.e_shentsize) + " (bytes)"; printFields(OS, "Size of section headers:", Str); @@ -4778,8 +4795,10 @@ void GNUELFDumper<ELFT>::printProgramHeaders( return; if (PrintProgramHeaders) { - const Elf_Ehdr &Header = this->Obj.getHeader(); - if (Header.e_phnum == 0) { + Expected<uint32_t> PhNumOrErr = this->Obj.getPhNum(); + if (!PhNumOrErr) { + OS << '\n' << errorToErrorCode(PhNumOrErr.takeError()).message() << '\n'; + } else if (*PhNumOrErr == 0) { OS << "\nThere are no program headers in this file.\n"; } else { printProgramHeaders(); @@ -4795,10 +4814,18 @@ template <class ELFT> void GNUELFDumper<ELFT>::printProgramHeaders() { const Elf_Ehdr &Header = this->Obj.getHeader(); Field Fields[8] = {2, 17, 26, 37 + Bias, 48 + Bias, 56 + Bias, 64 + Bias, 68 + Bias}; + uint32_t PhNum; + if (Expected<uint32_t> PhNumOrErr = this->Obj.getPhNum()) + PhNum = *PhNumOrErr; + else { + OS << '\n' << errorToErrorCode(PhNumOrErr.takeError()).message() << '\n'; + return; + } + OS << "\nElf file type is " << enumToString(Header.e_type, ArrayRef(ElfObjectFileType)) << "\n" << "Entry point " << format_hex(Header.e_entry, 3) << "\n" - << "There are " << Header.e_phnum << " program headers," + << "There are " << PhNum << " program headers," << " starting at offset " << Header.e_phoff << "\n\n" << "Program Headers:\n"; if (ELFT::Is64Bits) @@ -7470,7 +7497,8 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printFileHeaders() { W.printFlags("Flags", E.e_flags); W.printNumber("HeaderSize", E.e_ehsize); W.printNumber("ProgramHeaderEntrySize", E.e_phentsize); - W.printNumber("ProgramHeaderCount", E.e_phnum); + W.printString("ProgramHeaderCount", + getProgramHeadersNumString(this->Obj, this->FileName)); W.printNumber("SectionHeaderEntrySize", E.e_shentsize); W.printString("SectionHeaderCount", getSectionHeadersNumString(this->Obj, this->FileName)); `````````` </details> https://github.com/llvm/llvm-project/pull/165278 _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
