Skip to content

Commit 70f9399

Browse files
committed
[llvm-readobj, ELF] Support reading bianry has more than PN_XNUM segments
Some binary, like FreeBSD coredump, use program headers to store mmaps informations. It is possible for program to use more than PN_XNUM program headers. Therefore, we implemnet the support of PN_XNBUM in readelf and objcopy.
1 parent d2740bc commit 70f9399

File tree

4 files changed

+113
-18
lines changed

4 files changed

+113
-18
lines changed

llvm/test/tools/llvm-objcopy/ELF/many-sections.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ RUN: llvm-readobj --file-headers --sections --symbols %t2 | FileCheck %s
66
RUN: llvm-readelf --symbols %t2 | FileCheck --check-prefix=SYMS %s
77

88
## The ELF header should have e_shnum == 0 and e_shstrndx == SHN_XINDEX.
9-
# CHECK: SectionHeaderCount: 0
10-
# CHECK-NEXT: StringTableSectionIndex: 65535
9+
# CHECK: SectionHeaderCount: 0 (65540)
10+
# CHECK-NEXT: StringTableSectionIndex: 65535 (65539)
1111

1212
## The first section header should store the real section header count and
1313
## shstrndx in its fields.
930 KB
Binary file not shown.
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: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3572,12 +3572,30 @@ 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+
if (Obj.getHeader().e_phnum != ELF::PN_XNUM)
3579+
return to_string(Obj.getHeader().e_phnum);
3580+
3581+
Expected<ArrayRef<typename ELFT::Shdr>> ArrOrErr = Obj.sections();
3582+
if (!ArrOrErr) {
3583+
// In this case we can ignore an error, because we have already reported a
3584+
// warning about the broken section header table earlier.
3585+
consumeError(ArrOrErr.takeError());
3586+
return "<?>";
3587+
}
3588+
3589+
if (Obj.getHeader().e_phnum == Obj.getPhNum())
3590+
return "65535";
3591+
return "65535 (" + to_string(Obj.getPhNum()) + ")";
3592+
}
3593+
35753594
template <class ELFT>
35763595
static std::string getSectionHeadersNumString(const ELFFile<ELFT> &Obj,
35773596
StringRef FileName) {
3578-
const typename ELFT::Ehdr &ElfHeader = Obj.getHeader();
3579-
if (ElfHeader.e_shnum != 0)
3580-
return to_string(ElfHeader.e_shnum);
3597+
if (Obj.getHeader().e_shnum != 0)
3598+
return to_string(Obj.getHeader().e_shnum);
35813599

35823600
Expected<ArrayRef<typename ELFT::Shdr>> ArrOrErr = Obj.sections();
35833601
if (!ArrOrErr) {
@@ -3587,17 +3605,16 @@ static std::string getSectionHeadersNumString(const ELFFile<ELFT> &Obj,
35873605
return "<?>";
35883606
}
35893607

3590-
if (ArrOrErr->empty())
3608+
if (Obj.getHeader().e_shnum == Obj.getShNum())
35913609
return "0";
3592-
return "0 (" + to_string((*ArrOrErr)[0].sh_size) + ")";
3610+
return "0 (" + to_string(Obj.getShNum()) + ")";
35933611
}
35943612

35953613
template <class ELFT>
35963614
static std::string getSectionHeaderTableIndexString(const ELFFile<ELFT> &Obj,
35973615
StringRef FileName) {
3598-
const typename ELFT::Ehdr &ElfHeader = Obj.getHeader();
3599-
if (ElfHeader.e_shstrndx != SHN_XINDEX)
3600-
return to_string(ElfHeader.e_shstrndx);
3616+
if (Obj.getHeader().e_shstrndx != SHN_XINDEX)
3617+
return to_string(Obj.getHeader().e_shstrndx);
36013618

36023619
Expected<ArrayRef<typename ELFT::Shdr>> ArrOrErr = Obj.sections();
36033620
if (!ArrOrErr) {
@@ -3607,10 +3624,9 @@ static std::string getSectionHeaderTableIndexString(const ELFFile<ELFT> &Obj,
36073624
return "<?>";
36083625
}
36093626

3610-
if (ArrOrErr->empty())
3627+
if (Obj.getHeader().e_shstrndx == Obj.getShStrNdx())
36113628
return "65535 (corrupt: out of range)";
3612-
return to_string(ElfHeader.e_shstrndx) + " (" +
3613-
to_string((*ArrOrErr)[0].sh_link) + ")";
3629+
return "65535 (" + to_string(Obj.getShStrNdx()) + ")";
36143630
}
36153631

36163632
static const EnumEntry<unsigned> *getObjectFileEnumEntry(unsigned Type) {
@@ -3765,7 +3781,7 @@ template <class ELFT> void GNUELFDumper<ELFT>::printFileHeaders() {
37653781
printFields(OS, "Size of this header:", Str);
37663782
Str = to_string(e.e_phentsize) + " (bytes)";
37673783
printFields(OS, "Size of program headers:", Str);
3768-
Str = to_string(e.e_phnum);
3784+
Str = getProgramHeadersNumString(this->Obj, this->FileName);
37693785
printFields(OS, "Number of program headers:", Str);
37703786
Str = to_string(e.e_shentsize) + " (bytes)";
37713787
printFields(OS, "Size of section headers:", Str);
@@ -4778,8 +4794,7 @@ void GNUELFDumper<ELFT>::printProgramHeaders(
47784794
return;
47794795

47804796
if (PrintProgramHeaders) {
4781-
const Elf_Ehdr &Header = this->Obj.getHeader();
4782-
if (Header.e_phnum == 0) {
4797+
if (this->Obj.getPhNum() == 0) {
47834798
OS << "\nThere are no program headers in this file.\n";
47844799
} else {
47854800
printProgramHeaders();
@@ -4798,7 +4813,7 @@ template <class ELFT> void GNUELFDumper<ELFT>::printProgramHeaders() {
47984813
OS << "\nElf file type is "
47994814
<< enumToString(Header.e_type, ArrayRef(ElfObjectFileType)) << "\n"
48004815
<< "Entry point " << format_hex(Header.e_entry, 3) << "\n"
4801-
<< "There are " << Header.e_phnum << " program headers,"
4816+
<< "There are " << this->Obj.getPhNum() << " program headers,"
48024817
<< " starting at offset " << Header.e_phoff << "\n\n"
48034818
<< "Program Headers:\n";
48044819
if (ELFT::Is64Bits)
@@ -7470,7 +7485,8 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printFileHeaders() {
74707485
W.printFlags("Flags", E.e_flags);
74717486
W.printNumber("HeaderSize", E.e_ehsize);
74727487
W.printNumber("ProgramHeaderEntrySize", E.e_phentsize);
7473-
W.printNumber("ProgramHeaderCount", E.e_phnum);
7488+
W.printString("ProgramHeaderCount",
7489+
getProgramHeadersNumString(this->Obj, this->FileName));
74747490
W.printNumber("SectionHeaderEntrySize", E.e_shentsize);
74757491
W.printString("SectionHeaderCount",
74767492
getSectionHeadersNumString(this->Obj, this->FileName));

0 commit comments

Comments
 (0)