Skip to content

Commit fe99baf

Browse files
committed
[llvm-readobj, ELF] Support reading binary with more than PN_XNUM segments.
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.
1 parent cb48096 commit fe99baf

File tree

4 files changed

+168
-22
lines changed

4 files changed

+168
-22
lines changed
930 KB
Binary file not shown.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# RUN: yaml2obj --docnum=1 %s -o %t.o
2+
3+
# RUN: llvm-readobj --headers %t.o 2>&1 | FileCheck %s --check-prefix=CASE-INVALID
4+
5+
# CASE-INVALID: SectionHeaderOffset: 0
6+
# CASE-INVALID: ProgramHeaderCount: 65535 (corrupt)
7+
# 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
8+
9+
--- !ELF
10+
FileHeader:
11+
Class: ELFCLASS64
12+
Data: ELFDATA2LSB
13+
Type: ET_EXEC
14+
Machine: EM_X86_64
15+
EPhNum: 65535
16+
EShOff: 0
17+
ProgramHeaders:
18+
- Type: PT_LOAD
19+
20+
# RUN: yaml2obj --docnum=2 %s -o %t2.o
21+
22+
# RUN: llvm-readobj --headers %t2.o 2>&1 | FileCheck %s --check-prefix=CASE-VALID
23+
24+
# CASE-VALID: SectionHeaderOffset: 0
25+
# CASE-VALID: ProgramHeaderCount: 65535 (65536)
26+
# 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
27+
28+
--- !ELF
29+
FileHeader:
30+
Class: ELFCLASS64
31+
Data: ELFDATA2LSB
32+
Type: ET_EXEC
33+
Machine: EM_X86_64
34+
EPhNum: 65535
35+
Sections:
36+
- Type: SHT_NULL
37+
Info: 65536
38+
ProgramHeaders:
39+
- Type: PT_LOAD
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
## Show that llvm-readelf can handle an input file with many segments.
2+
3+
RUN: %python %p/../../llvm-objcopy/Inputs/ungzip.py %p/Inputs/many-segments.o.gz > %t
4+
RUN: llvm-readobj --file-headers --sections --segments %t | FileCheck %s
5+
RUN: llvm-readelf --segments %t | FileCheck --check-prefix=SYMS %s
6+
7+
## The ELF header should have e_phnum == PN_XNUM
8+
# CHECK: ProgramHeaderCount: 65535 (66549)
9+
## The first section header should store the real program header count in its fields.
10+
# CHECK: Section {
11+
# CHECK-NEXT: Index: 0
12+
# CHECK-NEXT: Name:
13+
# CHECK-NEXT: Type: SHT_NULL
14+
# CHECK-NEXT: Flags [
15+
# CHECK-NEXT: ]
16+
# CHECK-NEXT: Address:
17+
# CHECK-NEXT: Offset:
18+
# CHECK-NEXT: Size:
19+
# CHECK-NEXT: Link:
20+
# CHECK-NEXT: Info: 66549
21+
22+
## Show that the symbols with segments indexes around the reserved range still
23+
## have the right segment indexes afterwards.
24+
# 65535th segment
25+
# CHECK: Offset: 0x1183B000
26+
# CHECK-NEXT: VirtualAddress: 0x349139F3000
27+
# CHECK: }
28+
# CHECK-NEXT ProgramHeader {
29+
# CHECK-NEXT Type: PT_LOAD (0x1)
30+
# CHECK-NEXT Offset: 0x1183C000
31+
# CHECK-NEXT VirtualAddress: 0x349139F4000
32+
# CHECK-NEXT PhysicalAddress: 0x0
33+
# CHECK-NEXT FileSize: 4096
34+
# CHECK-NEXT MemSize: 4096
35+
# CHECK-NEXT Flags [ (0x4)
36+
# CHECK-NEXT PF_R (0x4)
37+
# CHECK-NEXT ]
38+
# CHECK-NEXT Alignment: 4096
39+
# CHECK-NEXT }
40+
# CHECK-NEXT ProgramHeader {
41+
# CHECK-NEXT Type: PT_LOAD (0x1)
42+
# CHECK-NEXT Offset: 0x1183D000
43+
# CHECK-NEXT VirtualAddress: 0x349139F5000
44+
# CHECK-NEXT PhysicalAddress: 0x0
45+
# CHECK-NEXT FileSize: 4096
46+
# CHECK-NEXT MemSize: 4096
47+
# CHECK-NEXT Flags [ (0x6)
48+
# CHECK-NEXT PF_R (0x4)
49+
# CHECK-NEXT PF_W (0x2)
50+
# CHECK-NEXT ]
51+
# CHECK-NEXT Alignment: 4096
52+
# CHECK-NEXT }
53+
# CHECK-NEXT ProgramHeader {
54+
# CHECK-NEXT Type: PT_LOAD (0x1)
55+
# CHECK-NEXT Offset: 0x1183E000
56+
# CHECK-NEXT VirtualAddress: 0x349139F6000
57+
# CHECK-NEXT PhysicalAddress: 0x0
58+
# CHECK-NEXT FileSize: 4096
59+
# CHECK-NEXT MemSize: 4096
60+
# CHECK-NEXT Flags [ (0x4)
61+
# CHECK-NEXT PF_R (0x4)
62+
# CHECK-NEXT ]
63+
# CHECK-NEXT Alignment: 4096
64+
# CHECK-NEXT }
65+
# CHECK ProgramHeader {
66+
# CHECK-NEXT Type: PT_LOAD (0x1)
67+
# CHECK-NEXT Offset: 0x11C31000
68+
# CHECK-NEXT VirtualAddress: 0x30D8E7868000
69+
# CHECK-NEXT PhysicalAddress: 0x0
70+
# CHECK-NEXT FileSize: 8192
71+
# CHECK-NEXT MemSize: 8192
72+
# CHECK-NEXT Flags [ (0x6)
73+
# CHECK-NEXT PF_R (0x4)
74+
# CHECK-NEXT PF_W (0x2)
75+
# CHECK-NEXT ]
76+
# CHECK-NEXT Alignment: 4096
77+
# CHECK-NEXT }
78+
79+
# SYMS: There are 66549 program headers, starting at offset 64

llvm/tools/llvm-readobj/ELFDumper.cpp

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3572,45 +3572,62 @@ static inline void printFields(formatted_raw_ostream &OS, StringRef Str1,
35723572
OS.flush();
35733573
}
35743574

3575+
template <class ELFT>
3576+
static std::string getProgramHeadersNumString(const ELFFile<ELFT> &Obj,
3577+
StringRef FileName) {
3578+
3579+
if (Obj.getHeader().e_phnum != ELF::PN_XNUM)
3580+
return to_string(Obj.getHeader().e_phnum);
3581+
3582+
Expected<uint32_t> PhNumOrErr = Obj.getPhNum();
3583+
if (!PhNumOrErr) {
3584+
// In this case we can ignore an error, because we have already reported a
3585+
// warning about the broken section header table earlier.
3586+
consumeError(PhNumOrErr.takeError());
3587+
return "<?>";
3588+
}
3589+
3590+
if (*PhNumOrErr == ELF::PN_XNUM)
3591+
return "65535 (corrupt)";
3592+
return "65535 (" + to_string(*PhNumOrErr) + ")";
3593+
}
3594+
35753595
template <class ELFT>
35763596
static std::string getSectionHeadersNumString(const ELFFile<ELFT> &Obj,
35773597
StringRef FileName) {
3578-
const typename ELFT::Ehdr &ElfHeader = Obj.getHeader();
3579-
if (ElfHeader.e_shnum != 0)
3580-
return to_string(ElfHeader.e_shnum);
3598+
if (Obj.getHeader().e_shnum != 0)
3599+
return to_string(Obj.getHeader().e_shnum);
35813600

3582-
Expected<ArrayRef<typename ELFT::Shdr>> ArrOrErr = Obj.sections();
3583-
if (!ArrOrErr) {
3601+
Expected<uint64_t> ShNumOrErr = Obj.getShNum();
3602+
if (!ShNumOrErr) {
35843603
// In this case we can ignore an error, because we have already reported a
35853604
// warning about the broken section header table earlier.
3586-
consumeError(ArrOrErr.takeError());
3605+
consumeError(ShNumOrErr.takeError());
35873606
return "<?>";
35883607
}
35893608

3590-
if (ArrOrErr->empty())
3609+
if (*ShNumOrErr == 0)
35913610
return "0";
3592-
return "0 (" + to_string((*ArrOrErr)[0].sh_size) + ")";
3611+
return "0 (" + to_string(*ShNumOrErr) + ")";
35933612
}
35943613

35953614
template <class ELFT>
35963615
static std::string getSectionHeaderTableIndexString(const ELFFile<ELFT> &Obj,
35973616
StringRef FileName) {
3598-
const typename ELFT::Ehdr &ElfHeader = Obj.getHeader();
3599-
if (ElfHeader.e_shstrndx != SHN_XINDEX)
3600-
return to_string(ElfHeader.e_shstrndx);
3617+
if (Obj.getHeader().e_shstrndx != ELF::SHN_XINDEX)
3618+
return to_string(Obj.getHeader().e_shstrndx);
36013619

3602-
Expected<ArrayRef<typename ELFT::Shdr>> ArrOrErr = Obj.sections();
3603-
if (!ArrOrErr) {
3620+
Expected<uint32_t> ShStrNdxOrErr = Obj.getShStrNdx();
3621+
if (!ShStrNdxOrErr) {
36043622
// In this case we can ignore an error, because we have already reported a
36053623
// warning about the broken section header table earlier.
3606-
consumeError(ArrOrErr.takeError());
3624+
consumeError(ShStrNdxOrErr.takeError());
36073625
return "<?>";
36083626
}
36093627

3610-
if (ArrOrErr->empty())
3628+
if (*ShStrNdxOrErr == ELF::SHN_XINDEX)
36113629
return "65535 (corrupt: out of range)";
3612-
return to_string(ElfHeader.e_shstrndx) + " (" +
3613-
to_string((*ArrOrErr)[0].sh_link) + ")";
3630+
return "65535 (" + to_string(*ShStrNdxOrErr) + ")";
36143631
}
36153632

36163633
static const EnumEntry<unsigned> *getObjectFileEnumEntry(unsigned Type) {
@@ -3765,7 +3782,7 @@ template <class ELFT> void GNUELFDumper<ELFT>::printFileHeaders() {
37653782
printFields(OS, "Size of this header:", Str);
37663783
Str = to_string(e.e_phentsize) + " (bytes)";
37673784
printFields(OS, "Size of program headers:", Str);
3768-
Str = to_string(e.e_phnum);
3785+
Str = getProgramHeadersNumString(this->Obj, this->FileName);
37693786
printFields(OS, "Number of program headers:", Str);
37703787
Str = to_string(e.e_shentsize) + " (bytes)";
37713788
printFields(OS, "Size of section headers:", Str);
@@ -4778,8 +4795,10 @@ void GNUELFDumper<ELFT>::printProgramHeaders(
47784795
return;
47794796

47804797
if (PrintProgramHeaders) {
4781-
const Elf_Ehdr &Header = this->Obj.getHeader();
4782-
if (Header.e_phnum == 0) {
4798+
Expected<uint32_t> PhNumOrErr = this->Obj.getPhNum();
4799+
if (!PhNumOrErr) {
4800+
OS << '\n' << errorToErrorCode(PhNumOrErr.takeError()).message() << '\n';
4801+
} else if (*PhNumOrErr == 0) {
47834802
OS << "\nThere are no program headers in this file.\n";
47844803
} else {
47854804
printProgramHeaders();
@@ -4795,10 +4814,18 @@ template <class ELFT> void GNUELFDumper<ELFT>::printProgramHeaders() {
47954814
const Elf_Ehdr &Header = this->Obj.getHeader();
47964815
Field Fields[8] = {2, 17, 26, 37 + Bias,
47974816
48 + Bias, 56 + Bias, 64 + Bias, 68 + Bias};
4817+
uint32_t PhNum;
4818+
if (Expected<uint32_t> PhNumOrErr = this->Obj.getPhNum())
4819+
PhNum = *PhNumOrErr;
4820+
else {
4821+
OS << '\n' << errorToErrorCode(PhNumOrErr.takeError()).message() << '\n';
4822+
return;
4823+
}
4824+
47984825
OS << "\nElf file type is "
47994826
<< enumToString(Header.e_type, ArrayRef(ElfObjectFileType)) << "\n"
48004827
<< "Entry point " << format_hex(Header.e_entry, 3) << "\n"
4801-
<< "There are " << Header.e_phnum << " program headers,"
4828+
<< "There are " << PhNum << " program headers,"
48024829
<< " starting at offset " << Header.e_phoff << "\n\n"
48034830
<< "Program Headers:\n";
48044831
if (ELFT::Is64Bits)
@@ -7470,7 +7497,8 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printFileHeaders() {
74707497
W.printFlags("Flags", E.e_flags);
74717498
W.printNumber("HeaderSize", E.e_ehsize);
74727499
W.printNumber("ProgramHeaderEntrySize", E.e_phentsize);
7473-
W.printNumber("ProgramHeaderCount", E.e_phnum);
7500+
W.printString("ProgramHeaderCount",
7501+
getProgramHeadersNumString(this->Obj, this->FileName));
74747502
W.printNumber("SectionHeaderEntrySize", E.e_shentsize);
74757503
W.printString("SectionHeaderCount",
74767504
getSectionHeadersNumString(this->Obj, this->FileName));

0 commit comments

Comments
 (0)