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

Reply via email to