1 //===--- DwarfCFIEHPrinter.h - DWARF-based Unwind Information Printer -----===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_TOOLS_LLVM_READOBJ_DWARFCFIEHPRINTER_H
10 #define LLVM_TOOLS_LLVM_READOBJ_DWARFCFIEHPRINTER_H
12 #include "llvm-readobj.h"
13 #include "llvm/ADT/STLExtras.h"
14 #include "llvm/BinaryFormat/Dwarf.h"
15 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
16 #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
17 #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
18 #include "llvm/Object/ELF.h"
19 #include "llvm/Object/ELFObjectFile.h"
20 #include "llvm/Object/ELFTypes.h"
21 #include "llvm/Support/Casting.h"
22 #include "llvm/Support/Debug.h"
23 #include "llvm/Support/Endian.h"
24 #include "llvm/Support/Format.h"
25 #include "llvm/Support/ScopedPrinter.h"
26 #include "llvm/Support/type_traits.h"
29 namespace DwarfCFIEH
{
31 template <typename ELFT
> class PrinterContext
{
32 using Elf_Shdr
= typename
ELFT::Shdr
;
33 using Elf_Phdr
= typename
ELFT::Phdr
;
36 const object::ELFObjectFile
<ELFT
> &ObjF
;
38 void printEHFrameHdr(const Elf_Phdr
*EHFramePHdr
) const;
39 void printEHFrame(const Elf_Shdr
*EHFrameShdr
) const;
42 PrinterContext(ScopedPrinter
&W
, const object::ELFObjectFile
<ELFT
> &ObjF
)
45 void printUnwindInformation() const;
49 static const typename
ELFT::Shdr
*
50 findSectionByAddress(const object::ELFObjectFile
<ELFT
> &ObjF
, uint64_t Addr
) {
51 Expected
<typename
ELFT::ShdrRange
> SectionsOrErr
=
52 ObjF
.getELFFile().sections();
54 reportError(SectionsOrErr
.takeError(), ObjF
.getFileName());
56 for (const typename
ELFT::Shdr
&Shdr
: *SectionsOrErr
)
57 if (Shdr
.sh_addr
== Addr
)
62 template <typename ELFT
>
63 void PrinterContext
<ELFT
>::printUnwindInformation() const {
64 const object::ELFFile
<ELFT
> &Obj
= ObjF
.getELFFile();
66 Expected
<typename
ELFT::PhdrRange
> PhdrsOrErr
= Obj
.program_headers();
68 reportError(PhdrsOrErr
.takeError(), ObjF
.getFileName());
70 for (const Elf_Phdr
&Phdr
: *PhdrsOrErr
) {
71 if (Phdr
.p_type
!= ELF::PT_GNU_EH_FRAME
)
74 if (Phdr
.p_memsz
!= Phdr
.p_filesz
)
75 reportError(object::createError(
76 "p_memsz does not match p_filesz for GNU_EH_FRAME"),
78 printEHFrameHdr(&Phdr
);
82 Expected
<typename
ELFT::ShdrRange
> SectionsOrErr
= Obj
.sections();
84 reportError(SectionsOrErr
.takeError(), ObjF
.getFileName());
86 for (const Elf_Shdr
&Shdr
: *SectionsOrErr
) {
87 Expected
<StringRef
> NameOrErr
= Obj
.getSectionName(Shdr
);
89 reportError(NameOrErr
.takeError(), ObjF
.getFileName());
90 if (*NameOrErr
== ".eh_frame")
95 template <typename ELFT
>
96 void PrinterContext
<ELFT
>::printEHFrameHdr(const Elf_Phdr
*EHFramePHdr
) const {
97 DictScope
L(W
, "EHFrameHeader");
98 uint64_t EHFrameHdrAddress
= EHFramePHdr
->p_vaddr
;
99 W
.startLine() << format("Address: 0x%" PRIx64
"\n", EHFrameHdrAddress
);
100 W
.startLine() << format("Offset: 0x%" PRIx64
"\n", (uint64_t)EHFramePHdr
->p_offset
);
101 W
.startLine() << format("Size: 0x%" PRIx64
"\n", (uint64_t)EHFramePHdr
->p_memsz
);
103 const object::ELFFile
<ELFT
> &Obj
= ObjF
.getELFFile();
104 if (const Elf_Shdr
*EHFrameHdr
=
105 findSectionByAddress(ObjF
, EHFramePHdr
->p_vaddr
)) {
106 Expected
<StringRef
> NameOrErr
= Obj
.getSectionName(*EHFrameHdr
);
108 reportError(NameOrErr
.takeError(), ObjF
.getFileName());
109 W
.printString("Corresponding Section", *NameOrErr
);
112 Expected
<ArrayRef
<uint8_t>> Content
= Obj
.getSegmentContents(*EHFramePHdr
);
114 reportError(Content
.takeError(), ObjF
.getFileName());
116 DataExtractor
DE(*Content
, ELFT::Endianness
== llvm::endianness::little
,
117 ELFT::Is64Bits
? 8 : 4);
119 DictScope
D(W
, "Header");
122 auto Version
= DE
.getU8(&Offset
);
123 W
.printNumber("version", Version
);
126 object::createError("only version 1 of .eh_frame_hdr is supported"),
129 uint64_t EHFramePtrEnc
= DE
.getU8(&Offset
);
130 W
.startLine() << format("eh_frame_ptr_enc: 0x%" PRIx64
"\n", EHFramePtrEnc
);
131 if (EHFramePtrEnc
!= (dwarf::DW_EH_PE_pcrel
| dwarf::DW_EH_PE_sdata4
))
132 reportError(object::createError("unexpected encoding eh_frame_ptr_enc"),
135 uint64_t FDECountEnc
= DE
.getU8(&Offset
);
136 W
.startLine() << format("fde_count_enc: 0x%" PRIx64
"\n", FDECountEnc
);
137 if (FDECountEnc
!= dwarf::DW_EH_PE_udata4
)
138 reportError(object::createError("unexpected encoding fde_count_enc"),
141 uint64_t TableEnc
= DE
.getU8(&Offset
);
142 W
.startLine() << format("table_enc: 0x%" PRIx64
"\n", TableEnc
);
143 if (TableEnc
!= (dwarf::DW_EH_PE_datarel
| dwarf::DW_EH_PE_sdata4
))
144 reportError(object::createError("unexpected encoding table_enc"),
147 auto EHFramePtr
= DE
.getSigned(&Offset
, 4) + EHFrameHdrAddress
+ 4;
148 W
.startLine() << format("eh_frame_ptr: 0x%" PRIx64
"\n", EHFramePtr
);
150 auto FDECount
= DE
.getUnsigned(&Offset
, 4);
151 W
.printNumber("fde_count", FDECount
);
153 unsigned NumEntries
= 0;
155 while (Offset
+ 8 <= EHFramePHdr
->p_memsz
&& NumEntries
< FDECount
) {
156 DictScope
D(W
, std::string("entry ") + std::to_string(NumEntries
));
158 auto InitialPC
= DE
.getSigned(&Offset
, 4) + EHFrameHdrAddress
;
159 W
.startLine() << format("initial_location: 0x%" PRIx64
"\n", InitialPC
);
160 auto Address
= DE
.getSigned(&Offset
, 4) + EHFrameHdrAddress
;
161 W
.startLine() << format("address: 0x%" PRIx64
"\n", Address
);
163 if (InitialPC
< PrevPC
)
164 reportError(object::createError("initial_location is out of order"),
172 template <typename ELFT
>
173 void PrinterContext
<ELFT
>::printEHFrame(const Elf_Shdr
*EHFrameShdr
) const {
174 uint64_t Address
= EHFrameShdr
->sh_addr
;
175 uint64_t ShOffset
= EHFrameShdr
->sh_offset
;
176 W
.startLine() << format(".eh_frame section at offset 0x%" PRIx64
177 " address 0x%" PRIx64
":\n",
181 Expected
<ArrayRef
<uint8_t>> DataOrErr
=
182 ObjF
.getELFFile().getSectionContents(*EHFrameShdr
);
184 reportError(DataOrErr
.takeError(), ObjF
.getFileName());
186 // Construct DWARFDataExtractor to handle relocations ("PC Begin" fields).
187 std::unique_ptr
<DWARFContext
> DICtx
= DWARFContext::create(
188 ObjF
, DWARFContext::ProcessDebugRelocations::Process
, nullptr);
189 DWARFDataExtractor
DE(
190 DICtx
->getDWARFObj(), DICtx
->getDWARFObj().getEHFrameSection(),
191 ELFT::Endianness
== llvm::endianness::little
, ELFT::Is64Bits
? 8 : 4);
192 DWARFDebugFrame
EHFrame(Triple::ArchType(ObjF
.getArch()), /*IsEH=*/true,
193 /*EHFrameAddress=*/Address
);
194 if (Error E
= EHFrame
.parse(DE
))
195 reportError(std::move(E
), ObjF
.getFileName());
197 for (const dwarf::FrameEntry
&Entry
: EHFrame
) {
198 std::optional
<uint64_t> InitialLocation
;
199 if (const dwarf::CIE
*CIE
= dyn_cast
<dwarf::CIE
>(&Entry
)) {
200 W
.startLine() << format("[0x%" PRIx64
"] CIE length=%" PRIu64
"\n",
201 Address
+ CIE
->getOffset(), CIE
->getLength());
204 W
.printNumber("version", CIE
->getVersion());
205 W
.printString("augmentation", CIE
->getAugmentationString());
206 W
.printNumber("code_alignment_factor", CIE
->getCodeAlignmentFactor());
207 W
.printNumber("data_alignment_factor", CIE
->getDataAlignmentFactor());
208 W
.printNumber("return_address_register", CIE
->getReturnAddressRegister());
210 const dwarf::FDE
*FDE
= cast
<dwarf::FDE
>(&Entry
);
211 W
.startLine() << format("[0x%" PRIx64
"] FDE length=%" PRIu64
212 " cie=[0x%" PRIx64
"]\n",
213 Address
+ FDE
->getOffset(), FDE
->getLength(),
214 Address
+ FDE
->getLinkedCIE()->getOffset());
217 InitialLocation
= FDE
->getInitialLocation();
218 W
.startLine() << format("initial_location: 0x%" PRIx64
"\n",
220 W
.startLine() << format(
221 "address_range: 0x%" PRIx64
" (end : 0x%" PRIx64
")\n",
222 FDE
->getAddressRange(),
223 FDE
->getInitialLocation() + FDE
->getAddressRange());
226 W
.getOStream() << "\n";
227 W
.startLine() << "Program:\n";
229 auto DumpOpts
= DIDumpOptions();
230 DumpOpts
.IsEH
= true;
231 Entry
.cfis().dump(W
.getOStream(), DumpOpts
, W
.getIndentLevel(),
235 W
.getOStream() << "\n";
240 } // namespace DwarfCFIEH