mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-01 15:40:53 +00:00
[llvm-readobj] Impl GNU style program headers print
readelf -lW Differential Revision: http://reviews.llvm.org/D18372 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@264415 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
c9a0644f8a
commit
7a9b28aa44
BIN
test/tools/llvm-readobj/Inputs/phdrs-elf.exe-i386
Executable file
BIN
test/tools/llvm-readobj/Inputs/phdrs-elf.exe-i386
Executable file
Binary file not shown.
BIN
test/tools/llvm-readobj/Inputs/phdrs-elf.exe-x86_64
Executable file
BIN
test/tools/llvm-readobj/Inputs/phdrs-elf.exe-x86_64
Executable file
Binary file not shown.
78
test/tools/llvm-readobj/gnu-phdrs.test
Normal file
78
test/tools/llvm-readobj/gnu-phdrs.test
Normal file
@ -0,0 +1,78 @@
|
||||
#Source :
|
||||
#__thread int a = 1;
|
||||
#__thread int b;
|
||||
#
|
||||
#int main () {
|
||||
# b = 2;
|
||||
# throw (a + b) ;
|
||||
# return 0;
|
||||
#}
|
||||
# compiled as clang++ source.cpp
|
||||
# and clang++ -m32 source.cpp
|
||||
|
||||
RUN: llvm-readobj -program-headers %p/Inputs/phdrs-elf.exe-i386 --elf-output-style=GNU \
|
||||
RUN: | FileCheck %s -check-prefix ELF32
|
||||
RUN: llvm-readobj -program-headers %p/Inputs/phdrs-elf.exe-x86_64 \
|
||||
RUN: --elf-output-style=GNU | FileCheck %s -check-prefix ELF64
|
||||
|
||||
ELF32: Elf file type is EXEC (Executable file)
|
||||
ELF32-NEXT: Entry point 0x8048460
|
||||
ELF32-NEXT: There are 10 program headers, starting at offset 52
|
||||
|
||||
ELF32: Program Headers:
|
||||
ELF32-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
|
||||
ELF32-NEXT: PHDR 0x000034 0x08048034 0x08048034 0x00140 0x00140 R E 0x4
|
||||
ELF32-NEXT: INTERP 0x000174 0x08048174 0x08048174 0x00013 0x00013 R 0x1
|
||||
ELF32-NEXT: [Requesting program interpreter: /lib/ld-linux.so.2]
|
||||
ELF32-NEXT: LOAD 0x000000 0x08048000 0x08048000 0x006d0 0x006d0 R E 0x1000
|
||||
ELF32-NEXT: LOAD 0x000ef0 0x08049ef0 0x08049ef0 0x00128 0x00140 RW 0x1000
|
||||
ELF32-NEXT: DYNAMIC 0x000f08 0x08049f08 0x08049f08 0x000e8 0x000e8 RW 0x4
|
||||
ELF32-NEXT: NOTE 0x000188 0x08048188 0x08048188 0x00044 0x00044 R 0x4
|
||||
ELF32-NEXT: TLS 0x000ef0 0x08049ef0 0x08049ef0 0x00004 0x00008 R 0x4
|
||||
ELF32-NEXT: GNU_EH_FRAME 0x000640 0x08048640 0x08048640 0x0001c 0x0001c R 0x4
|
||||
ELF32-NEXT: GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4
|
||||
ELF32-NEXT: GNU_RELRO 0x000ef0 0x08049ef0 0x08049ef0 0x00110 0x00110 R 0x1
|
||||
|
||||
ELF32: Section to Segment mapping:
|
||||
ELF32-NEXT: Segment Sections...
|
||||
ELF32-NEXT: 00
|
||||
ELF32-NEXT: 01 .interp
|
||||
ELF32-NEXT: 02 .interp .note.ABI-tag .note.gnu.build-id .hash .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame
|
||||
ELF32-NEXT: 03 .tdata .ctors .dtors .jcr .dynamic .got .got.plt .data .bss
|
||||
ELF32-NEXT: 04 .dynamic
|
||||
ELF32-NEXT: 05 .note.ABI-tag .note.gnu.build-id
|
||||
ELF32-NEXT: 06 .tdata .tbss
|
||||
ELF32-NEXT: 07 .eh_frame_hdr
|
||||
ELF32-NEXT: 08
|
||||
ELF32-NEXT: 09 .tdata .ctors .dtors .jcr .dynamic .got
|
||||
|
||||
ELF64: Elf file type is EXEC (Executable file)
|
||||
ELF64-NEXT: Entry point 0x400610
|
||||
ELF64-NEXT: There are 10 program headers, starting at offset 64
|
||||
|
||||
ELF64: Program Headers:
|
||||
ELF64-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
|
||||
ELF64-NEXT: PHDR 0x000040 0x0000000000400040 0x0000000000400040 0x000230 0x000230 R E 0x8
|
||||
ELF64-NEXT: INTERP 0x000270 0x0000000000400270 0x0000000000400270 0x00001c 0x00001c R 0x1
|
||||
ELF64-NEXT: [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
|
||||
ELF64-NEXT: LOAD 0x000000 0x0000000000400000 0x0000000000400000 0x000924 0x000924 R E 0x200000
|
||||
ELF64-NEXT: LOAD 0x000db4 0x0000000000600db4 0x0000000000600db4 0x000274 0x0002a4 RW 0x200000
|
||||
ELF64-NEXT: DYNAMIC 0x000dd0 0x0000000000600dd0 0x0000000000600dd0 0x000210 0x000210 RW 0x8
|
||||
ELF64-NEXT: NOTE 0x00028c 0x000000000040028c 0x000000000040028c 0x000044 0x000044 R 0x4
|
||||
ELF64-NEXT: TLS 0x000db4 0x0000000000600db4 0x0000000000600db4 0x000004 0x000008 R 0x4
|
||||
ELF64-NEXT: GNU_EH_FRAME 0x00083c 0x000000000040083c 0x000000000040083c 0x00002c 0x00002c R 0x4
|
||||
ELF64-NEXT: GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x8
|
||||
ELF64-NEXT: GNU_RELRO 0x000db4 0x0000000000600db4 0x0000000000600db4 0x00024c 0x00024c R 0x1
|
||||
|
||||
ELF64: Section to Segment mapping:
|
||||
ELF64-NEXT: Segment Sections...
|
||||
ELF64-NEXT: 00
|
||||
ELF64-NEXT: 01 .interp
|
||||
ELF64-NEXT: 02 .interp .note.ABI-tag .note.gnu.build-id .hash .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame
|
||||
ELF64-NEXT: 03 .tdata .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss
|
||||
ELF64-NEXT: 04 .dynamic
|
||||
ELF64-NEXT: 05 .note.ABI-tag .note.gnu.build-id
|
||||
ELF64-NEXT: 06 .tdata .tbss
|
||||
ELF64-NEXT: 07 .eh_frame_hdr
|
||||
ELF64-NEXT: 08
|
||||
ELF64-NEXT: 09 .tdata .init_array .fini_array .jcr .dynamic .got
|
@ -279,6 +279,7 @@ public:
|
||||
virtual void printSymbol(const ELFFile<ELFT> *Obj, const Elf_Sym *Symbol,
|
||||
const Elf_Sym *FirstSym, StringRef StrTable,
|
||||
bool IsDynamic) = 0;
|
||||
virtual void printProgramHeaders(const ELFFile<ELFT> *Obj) = 0;
|
||||
const ELFDumper<ELFT> *dumper() const { return Dumper; }
|
||||
private:
|
||||
const ELFDumper<ELFT> *Dumper;
|
||||
@ -299,6 +300,7 @@ public:
|
||||
void printDynamicRelocations(const ELFO *Obj) override;
|
||||
virtual void printSymtabMessage(const ELFO *Obj, StringRef Name,
|
||||
size_t Offset) override;
|
||||
void printProgramHeaders(const ELFO *Obj) override;
|
||||
|
||||
private:
|
||||
struct Field {
|
||||
@ -329,6 +331,10 @@ private:
|
||||
StringRef StrTable, bool IsDynamic) override;
|
||||
std::string getSymbolSectionNdx(const ELFO *Obj, const Elf_Sym *Symbol,
|
||||
const Elf_Sym *FirstSym);
|
||||
bool checkTLSSections(const Elf_Phdr &Phdr, const Elf_Shdr &Sec);
|
||||
bool checkoffsets(const Elf_Phdr &Phdr, const Elf_Shdr &Sec);
|
||||
bool checkVMA(const Elf_Phdr &Phdr, const Elf_Shdr &Sec);
|
||||
bool checkPTDynamic(const Elf_Phdr &Phdr, const Elf_Shdr &Sec);
|
||||
};
|
||||
|
||||
template <typename ELFT> class LLVMStyle : public DumpStyle<ELFT> {
|
||||
@ -345,6 +351,7 @@ public:
|
||||
void printSymbols(const ELFO *Obj) override;
|
||||
void printDynamicSymbols(const ELFO *Obj) override;
|
||||
void printDynamicRelocations(const ELFO *Obj) override;
|
||||
void printProgramHeaders(const ELFO *Obj) override;
|
||||
|
||||
private:
|
||||
void printRelocation(const ELFO *Obj, Elf_Rela Rel, const Elf_Shdr *SymTab);
|
||||
@ -1076,6 +1083,65 @@ static const char *getElfSegmentType(unsigned Arch, unsigned Type) {
|
||||
}
|
||||
}
|
||||
|
||||
static std::string getElfPtType(unsigned Arch, unsigned Type) {
|
||||
switch (Type) {
|
||||
case ELF::PT_NULL:
|
||||
return "NULL";
|
||||
case ELF::PT_LOAD:
|
||||
return "LOAD";
|
||||
case ELF::PT_DYNAMIC:
|
||||
return "DYNAMIC";
|
||||
case ELF::PT_INTERP:
|
||||
return "INTERP";
|
||||
case ELF::PT_NOTE:
|
||||
return "NOTE";
|
||||
case ELF::PT_SHLIB:
|
||||
return "SHLIB";
|
||||
case ELF::PT_PHDR:
|
||||
return "PHDR";
|
||||
case ELF::PT_TLS:
|
||||
return "TLS";
|
||||
case ELF::PT_GNU_EH_FRAME:
|
||||
return "GNU_EH_FRAME";
|
||||
case ELF::PT_SUNW_UNWIND:
|
||||
return "SUNW_UNWIND";
|
||||
case ELF::PT_GNU_STACK:
|
||||
return "GNU_STACK";
|
||||
case ELF::PT_GNU_RELRO:
|
||||
return "GNU_RELRO";
|
||||
default:
|
||||
// All machine specific PT_* types
|
||||
switch (Arch) {
|
||||
case ELF::EM_AMDGPU:
|
||||
switch (Type) {
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, PT_AMDGPU_HSA_LOAD_GLOBAL_PROGRAM);
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, PT_AMDGPU_HSA_LOAD_GLOBAL_AGENT);
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, PT_AMDGPU_HSA_LOAD_READONLY_AGENT);
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, PT_AMDGPU_HSA_LOAD_CODE_AGENT);
|
||||
}
|
||||
return "";
|
||||
case ELF::EM_ARM:
|
||||
if (Type == ELF::PT_ARM_EXIDX)
|
||||
return "EXIDX";
|
||||
return "";
|
||||
case ELF::EM_MIPS:
|
||||
case ELF::EM_MIPS_RS3_LE:
|
||||
switch (Type) {
|
||||
case PT_MIPS_REGINFO:
|
||||
return "REGINFO";
|
||||
case PT_MIPS_RTPROC:
|
||||
return "RTPROC";
|
||||
case PT_MIPS_OPTIONS:
|
||||
return "OPTIONS";
|
||||
case PT_MIPS_ABIFLAGS:
|
||||
return "ABIFLAGS";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
return std::string("<unknown>: ") + to_string(format_hex(Type, 1));
|
||||
}
|
||||
|
||||
static const EnumEntry<unsigned> ElfSegmentFlags[] = {
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, PF_X),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, PF_W),
|
||||
@ -1313,11 +1379,14 @@ void ELFDumper<ELFT>::printRelocations() {
|
||||
ELFDumperStyle->printRelocations(Obj);
|
||||
}
|
||||
|
||||
template <class ELFT> void ELFDumper<ELFT>::printProgramHeaders() {
|
||||
ELFDumperStyle->printProgramHeaders(Obj);
|
||||
}
|
||||
|
||||
template <class ELFT> void ELFDumper<ELFT>::printDynamicRelocations() {
|
||||
ELFDumperStyle->printDynamicRelocations(Obj);
|
||||
}
|
||||
|
||||
|
||||
template<class ELFT>
|
||||
void ELFDumper<ELFT>::printSymbols() {
|
||||
ELFDumperStyle->printSymbols(Obj);
|
||||
@ -1328,7 +1397,6 @@ void ELFDumper<ELFT>::printDynamicSymbols() {
|
||||
ELFDumperStyle->printDynamicSymbols(Obj);
|
||||
}
|
||||
|
||||
|
||||
#define LLVM_READOBJ_TYPE_CASE(name) \
|
||||
case DT_##name: return #name
|
||||
|
||||
@ -1642,24 +1710,6 @@ void ELFDumper<ELFT>::printNeededLibraries() {
|
||||
}
|
||||
}
|
||||
|
||||
template<class ELFT>
|
||||
void ELFDumper<ELFT>::printProgramHeaders() {
|
||||
ListScope L(W, "ProgramHeaders");
|
||||
|
||||
for (const Elf_Phdr &Phdr : Obj->program_headers()) {
|
||||
DictScope P(W, "ProgramHeader");
|
||||
W.printHex("Type",
|
||||
getElfSegmentType(Obj->getHeader()->e_machine, Phdr.p_type),
|
||||
Phdr.p_type);
|
||||
W.printHex("Offset", Phdr.p_offset);
|
||||
W.printHex("VirtualAddress", Phdr.p_vaddr);
|
||||
W.printHex("PhysicalAddress", Phdr.p_paddr);
|
||||
W.printNumber("FileSize", Phdr.p_filesz);
|
||||
W.printNumber("MemSize", Phdr.p_memsz);
|
||||
W.printFlags("Flags", Phdr.p_flags, makeArrayRef(ElfSegmentFlags));
|
||||
W.printNumber("Alignment", Phdr.p_align);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ELFT>
|
||||
void ELFDumper<ELFT>::printHashTable() {
|
||||
@ -2648,6 +2698,143 @@ void GNUStyle<ELFT>::printDynamicSymbols(const ELFO *Obj) {
|
||||
this->dumper()->printSymbolsHelper(true);
|
||||
}
|
||||
|
||||
static inline std::string printPhdrFlags(unsigned Flag) {
|
||||
std::string Str;
|
||||
Str = (Flag & PF_R) ? "R" : " ";
|
||||
Str += (Flag & PF_W) ? "W" : " ";
|
||||
Str += (Flag & PF_X) ? "E" : " ";
|
||||
return Str;
|
||||
}
|
||||
|
||||
// SHF_TLS sections are only in PT_TLS, PT_LOAD or PT_GNU_RELRO
|
||||
// PT_TLS must only have SHF_TLS sections
|
||||
template <class ELFT>
|
||||
bool GNUStyle<ELFT>::checkTLSSections(const Elf_Phdr &Phdr,
|
||||
const Elf_Shdr &Sec) {
|
||||
return (((Sec.sh_flags & ELF::SHF_TLS) &&
|
||||
((Phdr.p_type == ELF::PT_TLS) || (Phdr.p_type == ELF::PT_LOAD) ||
|
||||
(Phdr.p_type == ELF::PT_GNU_RELRO))) ||
|
||||
(!(Sec.sh_flags & ELF::SHF_TLS) && Phdr.p_type != ELF::PT_TLS));
|
||||
}
|
||||
|
||||
// Non-SHT_NOBITS must have its offset inside the segment
|
||||
// Only non-zero section can be at end of segment
|
||||
template <class ELFT>
|
||||
bool GNUStyle<ELFT>::checkoffsets(const Elf_Phdr &Phdr, const Elf_Shdr &Sec) {
|
||||
if (Sec.sh_type == ELF::SHT_NOBITS)
|
||||
return true;
|
||||
bool IsSpecial =
|
||||
(Sec.sh_type == ELF::SHT_NOBITS) && ((Sec.sh_flags & ELF::SHF_TLS) != 0);
|
||||
// .tbss is special, it only has memory in PT_TLS and has NOBITS properties
|
||||
auto SectionSize =
|
||||
(IsSpecial && Phdr.p_type != ELF::PT_TLS) ? 0 : Sec.sh_size;
|
||||
if (Sec.sh_offset >= Phdr.p_offset)
|
||||
return ((Sec.sh_offset + SectionSize <= Phdr.p_filesz + Phdr.p_offset)
|
||||
/*only non-zero sized sections at end*/ &&
|
||||
(Sec.sh_offset + 1 <= Phdr.p_offset + Phdr.p_filesz));
|
||||
return false;
|
||||
}
|
||||
|
||||
// SHF_ALLOC must have VMA inside segment
|
||||
// Only non-zero section can be at end of segment
|
||||
template <class ELFT>
|
||||
bool GNUStyle<ELFT>::checkVMA(const Elf_Phdr &Phdr, const Elf_Shdr &Sec) {
|
||||
if (!(Sec.sh_flags & ELF::SHF_ALLOC))
|
||||
return true;
|
||||
bool IsSpecial =
|
||||
(Sec.sh_type == ELF::SHT_NOBITS) && ((Sec.sh_flags & ELF::SHF_TLS) != 0);
|
||||
// .tbss is special, it only has memory in PT_TLS and has NOBITS properties
|
||||
auto SectionSize =
|
||||
(IsSpecial && Phdr.p_type != ELF::PT_TLS) ? 0 : Sec.sh_size;
|
||||
if (Sec.sh_addr >= Phdr.p_vaddr)
|
||||
return ((Sec.sh_addr + SectionSize <= Phdr.p_vaddr + Phdr.p_memsz) &&
|
||||
(Sec.sh_addr + 1 <= Phdr.p_vaddr + Phdr.p_memsz));
|
||||
return false;
|
||||
}
|
||||
|
||||
// No section with zero size must be at start or end of PT_DYNAMIC
|
||||
template <class ELFT>
|
||||
bool GNUStyle<ELFT>::checkPTDynamic(const Elf_Phdr &Phdr, const Elf_Shdr &Sec) {
|
||||
if (Phdr.p_type != ELF::PT_DYNAMIC || Sec.sh_size != 0 || Phdr.p_memsz == 0)
|
||||
return true;
|
||||
// Is section within the phdr both based on offset and VMA ?
|
||||
return ((Sec.sh_type == ELF::SHT_NOBITS) ||
|
||||
(Sec.sh_offset > Phdr.p_offset &&
|
||||
Sec.sh_offset < Phdr.p_offset + Phdr.p_filesz)) &&
|
||||
(!(Sec.sh_flags & ELF::SHF_ALLOC) ||
|
||||
(Sec.sh_addr > Phdr.p_vaddr && Sec.sh_addr < Phdr.p_memsz));
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void GNUStyle<ELFT>::printProgramHeaders(const ELFO *Obj) {
|
||||
int Bias = (ELFT::Is64Bits) ? 8 : 0;
|
||||
unsigned Width = (ELFT::Is64Bits) ? 18 : 10;
|
||||
unsigned SizeWidth = (ELFT::Is64Bits) ? 8 : 7;
|
||||
std::string Type, Offset, VMA, LMA, FileSz, MemSz, Flag, Align;
|
||||
|
||||
const Elf_Ehdr *Header = Obj->getHeader();
|
||||
Field Fields[8] = {2, 17, 26, 37 + Bias,
|
||||
48 + Bias, 56 + Bias, 64 + Bias, 68 + Bias};
|
||||
OS << "\nElf file type is "
|
||||
<< printEnum(Header->e_type, makeArrayRef(ElfObjectFileType)) << "\n"
|
||||
<< "Entry point " << format_hex(Header->e_entry, 1) << "\n"
|
||||
<< "There are " << Header->e_phnum << " program headers,"
|
||||
<< " starting at offset " << Header->e_phoff << "\n\n"
|
||||
<< "Program Headers:\n";
|
||||
if (ELFT::Is64Bits)
|
||||
OS << " Type Offset VirtAddr PhysAddr "
|
||||
<< " FileSiz MemSiz Flg Align\n";
|
||||
else
|
||||
OS << " Type Offset VirtAddr PhysAddr FileSiz "
|
||||
<< "MemSiz Flg Align\n";
|
||||
for (const auto &Phdr : Obj->program_headers()) {
|
||||
Type = getElfPtType(Header->e_machine, Phdr.p_type);
|
||||
Offset = to_string(format_hex(Phdr.p_offset, 8));
|
||||
VMA = to_string(format_hex(Phdr.p_vaddr, Width));
|
||||
LMA = to_string(format_hex(Phdr.p_paddr, Width));
|
||||
FileSz = to_string(format_hex(Phdr.p_filesz, SizeWidth));
|
||||
MemSz = to_string(format_hex(Phdr.p_memsz, SizeWidth));
|
||||
Flag = printPhdrFlags(Phdr.p_flags);
|
||||
Align = to_string(format_hex(Phdr.p_align, 1));
|
||||
Fields[0].Str = Type;
|
||||
Fields[1].Str = Offset;
|
||||
Fields[2].Str = VMA;
|
||||
Fields[3].Str = LMA;
|
||||
Fields[4].Str = FileSz;
|
||||
Fields[5].Str = MemSz;
|
||||
Fields[6].Str = Flag;
|
||||
Fields[7].Str = Align;
|
||||
for (auto Field : Fields)
|
||||
printField(Field);
|
||||
if (Phdr.p_type == ELF::PT_INTERP) {
|
||||
OS << "\n [Requesting program interpreter: ";
|
||||
OS << reinterpret_cast<const char *>(Obj->base()) + Phdr.p_offset << "]";
|
||||
}
|
||||
OS << "\n";
|
||||
}
|
||||
OS << "\n Section to Segment mapping:\n Segment Sections...\n";
|
||||
int Phnum = 0;
|
||||
for (const Elf_Phdr &Phdr : Obj->program_headers()) {
|
||||
std::string Sections;
|
||||
OS << format(" %2.2d ", Phnum++);
|
||||
for (const Elf_Shdr &Sec : Obj->sections()) {
|
||||
// Check if each section is in a segment and then print mapping.
|
||||
// readelf additionally makes sure it does not print zero sized sections
|
||||
// at end of segments and for PT_DYNAMIC both start and end of section
|
||||
// .tbss must only be shown in PT_TLS section.
|
||||
bool TbssInNonTLS = (Sec.sh_type == ELF::SHT_NOBITS) &&
|
||||
((Sec.sh_flags & ELF::SHF_TLS) != 0) &&
|
||||
Phdr.p_type != ELF::PT_TLS;
|
||||
if (!TbssInNonTLS && checkTLSSections(Phdr, Sec) &&
|
||||
checkoffsets(Phdr, Sec) && checkVMA(Phdr, Sec) &&
|
||||
checkPTDynamic(Phdr, Sec) && (Sec.sh_type != ELF::SHT_NULL))
|
||||
Sections += unwrapOrError(Obj->getSectionName(&Sec)).str() + " ";
|
||||
}
|
||||
OS << Sections << "\n";
|
||||
OS.flush();
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) {
|
||||
OS << "GNU style dynamic relocations not implemented!\n";
|
||||
@ -2995,3 +3182,22 @@ void LLVMStyle<ELFT>::printDynamicRelocation(const ELFO *Obj, Elf_Rela Rel) {
|
||||
<< W.hex(Rel.r_addend) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void LLVMStyle<ELFT>::printProgramHeaders(const ELFO *Obj) {
|
||||
ListScope L(W, "ProgramHeaders");
|
||||
|
||||
for (const Elf_Phdr &Phdr : Obj->program_headers()) {
|
||||
DictScope P(W, "ProgramHeader");
|
||||
W.printHex("Type",
|
||||
getElfSegmentType(Obj->getHeader()->e_machine, Phdr.p_type),
|
||||
Phdr.p_type);
|
||||
W.printHex("Offset", Phdr.p_offset);
|
||||
W.printHex("VirtualAddress", Phdr.p_vaddr);
|
||||
W.printHex("PhysicalAddress", Phdr.p_paddr);
|
||||
W.printNumber("FileSize", Phdr.p_filesz);
|
||||
W.printNumber("MemSize", Phdr.p_memsz);
|
||||
W.printFlags("Flags", Phdr.p_flags, makeArrayRef(ElfSegmentFlags));
|
||||
W.printNumber("Alignment", Phdr.p_align);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user