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
13 #include "llvm-readobj.h"
14 #include "llvm/ADT/STLExtras.h"
15 #include "llvm/BinaryFormat/Dwarf.h"
16 #include "llvm/Object/ELF.h"
17 #include "llvm/Object/ELFTypes.h"
18 #include "llvm/Object/ELFObjectFile.h"
19 #include "llvm/Support/Casting.h"
20 #include "llvm/Support/ScopedPrinter.h"
21 #include "llvm/Support/Debug.h"
22 #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
23 #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
24 #include "llvm/Support/Endian.h"
25 #include "llvm/Support/Format.h"
26 #include "llvm/Support/type_traits.h"
29 namespace DwarfCFIEH
{
31 template <typename ELFT
>
32 class PrinterContext
{
34 const object::ELFObjectFile
<ELFT
> *ObjF
;
36 void printEHFrameHdr(uint64_t Offset
, uint64_t Address
, uint64_t Size
) const;
38 void printEHFrame(const typename
ELFT::Shdr
*EHFrameShdr
) const;
41 PrinterContext(ScopedPrinter
&W
, const object::ELFObjectFile
<ELFT
> *ObjF
)
44 void printUnwindInformation() const;
48 static const typename
object::ELFObjectFile
<ELFT
>::Elf_Shdr
*
49 findSectionByAddress(const object::ELFObjectFile
<ELFT
> *ObjF
, uint64_t Addr
) {
50 auto Sections
= ObjF
->getELFFile()->sections();
51 if (Error E
= Sections
.takeError())
52 reportError(std::move(E
), ObjF
->getFileName());
54 for (const auto &Shdr
: *Sections
)
55 if (Shdr
.sh_addr
== Addr
)
60 template <typename ELFT
>
61 void PrinterContext
<ELFT
>::printUnwindInformation() const {
62 const object::ELFFile
<ELFT
> *Obj
= ObjF
->getELFFile();
63 const typename
ELFT::Phdr
*EHFramePhdr
= nullptr;
65 auto PHs
= Obj
->program_headers();
66 if (Error E
= PHs
.takeError())
67 reportError(std::move(E
), ObjF
->getFileName());
69 for (const auto &Phdr
: *PHs
) {
70 if (Phdr
.p_type
== ELF::PT_GNU_EH_FRAME
) {
72 if (Phdr
.p_memsz
!= Phdr
.p_filesz
)
73 reportError(object::createError(
74 "p_memsz does not match p_filesz for GNU_EH_FRAME"),
81 printEHFrameHdr(EHFramePhdr
->p_offset
, EHFramePhdr
->p_vaddr
,
82 EHFramePhdr
->p_memsz
);
84 auto Sections
= Obj
->sections();
85 if (Error E
= Sections
.takeError())
86 reportError(std::move(E
), ObjF
->getFileName());
88 for (const auto &Shdr
: *Sections
) {
89 auto SectionName
= Obj
->getSectionName(&Shdr
);
90 if (Error E
= SectionName
.takeError())
91 reportError(std::move(E
), ObjF
->getFileName());
93 if (*SectionName
== ".eh_frame")
98 template <typename ELFT
>
99 void PrinterContext
<ELFT
>::printEHFrameHdr(uint64_t EHFrameHdrOffset
,
100 uint64_t EHFrameHdrAddress
,
101 uint64_t EHFrameHdrSize
) const {
102 ListScope
L(W
, "EH_FRAME Header");
103 W
.startLine() << format("Address: 0x%" PRIx64
"\n", EHFrameHdrAddress
);
104 W
.startLine() << format("Offset: 0x%" PRIx64
"\n", EHFrameHdrOffset
);
105 W
.startLine() << format("Size: 0x%" PRIx64
"\n", EHFrameHdrSize
);
107 const object::ELFFile
<ELFT
> *Obj
= ObjF
->getELFFile();
108 const auto *EHFrameHdrShdr
= findSectionByAddress(ObjF
, EHFrameHdrAddress
);
109 if (EHFrameHdrShdr
) {
110 auto SectionName
= Obj
->getSectionName(EHFrameHdrShdr
);
111 if (Error E
= SectionName
.takeError())
112 reportError(std::move(E
), ObjF
->getFileName());
114 W
.printString("Corresponding Section", *SectionName
);
117 DataExtractor
DE(makeArrayRef(Obj
->base() + EHFrameHdrOffset
, EHFrameHdrSize
),
118 ELFT::TargetEndianness
== support::endianness::little
,
119 ELFT::Is64Bits
? 8 : 4);
121 DictScope
D(W
, "Header");
124 auto Version
= DE
.getU8(&Offset
);
125 W
.printNumber("version", Version
);
128 object::createError("only version 1 of .eh_frame_hdr is supported"),
129 ObjF
->getFileName());
131 uint64_t EHFramePtrEnc
= DE
.getU8(&Offset
);
132 W
.startLine() << format("eh_frame_ptr_enc: 0x%" PRIx64
"\n", EHFramePtrEnc
);
133 if (EHFramePtrEnc
!= (dwarf::DW_EH_PE_pcrel
| dwarf::DW_EH_PE_sdata4
))
134 reportError(object::createError("unexpected encoding eh_frame_ptr_enc"),
135 ObjF
->getFileName());
137 uint64_t FDECountEnc
= DE
.getU8(&Offset
);
138 W
.startLine() << format("fde_count_enc: 0x%" PRIx64
"\n", FDECountEnc
);
139 if (FDECountEnc
!= dwarf::DW_EH_PE_udata4
)
140 reportError(object::createError("unexpected encoding fde_count_enc"),
141 ObjF
->getFileName());
143 uint64_t TableEnc
= DE
.getU8(&Offset
);
144 W
.startLine() << format("table_enc: 0x%" PRIx64
"\n", TableEnc
);
145 if (TableEnc
!= (dwarf::DW_EH_PE_datarel
| dwarf::DW_EH_PE_sdata4
))
146 reportError(object::createError("unexpected encoding table_enc"),
147 ObjF
->getFileName());
149 auto EHFramePtr
= DE
.getSigned(&Offset
, 4) + EHFrameHdrAddress
+ 4;
150 W
.startLine() << format("eh_frame_ptr: 0x%" PRIx64
"\n", EHFramePtr
);
152 auto FDECount
= DE
.getUnsigned(&Offset
, 4);
153 W
.printNumber("fde_count", FDECount
);
155 unsigned NumEntries
= 0;
157 while (Offset
+ 8 <= EHFrameHdrSize
&& NumEntries
< FDECount
) {
158 DictScope
D(W
, std::string("entry ") + std::to_string(NumEntries
));
160 auto InitialPC
= DE
.getSigned(&Offset
, 4) + EHFrameHdrAddress
;
161 W
.startLine() << format("initial_location: 0x%" PRIx64
"\n", InitialPC
);
162 auto Address
= DE
.getSigned(&Offset
, 4) + EHFrameHdrAddress
;
163 W
.startLine() << format("address: 0x%" PRIx64
"\n", Address
);
165 if (InitialPC
< PrevPC
)
166 reportError(object::createError("initial_location is out of order"),
167 ObjF
->getFileName());
174 template <typename ELFT
>
175 void PrinterContext
<ELFT
>::printEHFrame(
176 const typename
ELFT::Shdr
*EHFrameShdr
) const {
177 uint64_t Address
= EHFrameShdr
->sh_addr
;
178 uint64_t ShOffset
= EHFrameShdr
->sh_offset
;
179 W
.startLine() << format(".eh_frame section at offset 0x%" PRIx64
180 " address 0x%" PRIx64
":\n",
184 const object::ELFFile
<ELFT
> *Obj
= ObjF
->getELFFile();
185 auto Result
= Obj
->getSectionContents(EHFrameShdr
);
186 if (Error E
= Result
.takeError())
187 reportError(std::move(E
), ObjF
->getFileName());
189 auto Contents
= Result
.get();
190 DWARFDataExtractor
DE(
191 StringRef(reinterpret_cast<const char *>(Contents
.data()),
193 ELFT::TargetEndianness
== support::endianness::little
,
194 ELFT::Is64Bits
? 8 : 4);
195 DWARFDebugFrame
EHFrame(Triple::ArchType(ObjF
->getArch()), /*IsEH=*/true,
196 /*EHFrameAddress=*/Address
);
199 for (const auto &Entry
: EHFrame
) {
200 if (const auto *CIE
= dyn_cast
<dwarf::CIE
>(&Entry
)) {
201 W
.startLine() << format("[0x%" PRIx64
"] CIE length=%" PRIu64
"\n",
202 Address
+ CIE
->getOffset(),
206 W
.printNumber("version", CIE
->getVersion());
207 W
.printString("augmentation", CIE
->getAugmentationString());
208 W
.printNumber("code_alignment_factor", CIE
->getCodeAlignmentFactor());
209 W
.printNumber("data_alignment_factor", CIE
->getDataAlignmentFactor());
210 W
.printNumber("return_address_register", CIE
->getReturnAddressRegister());
212 W
.getOStream() << "\n";
213 W
.startLine() << "Program:\n";
215 CIE
->cfis().dump(W
.getOStream(), nullptr, W
.getIndentLevel());
219 W
.getOStream() << "\n";
221 } else if (const auto *FDE
= dyn_cast
<dwarf::FDE
>(&Entry
)) {
222 W
.startLine() << format("[0x%" PRIx64
"] FDE length=%" PRIu64
223 " cie=[0x%" PRIx64
"]\n",
224 Address
+ FDE
->getOffset(),
226 Address
+ FDE
->getLinkedCIE()->getOffset());
229 W
.startLine() << format("initial_location: 0x%" PRIx64
"\n",
230 FDE
->getInitialLocation());
232 << format("address_range: 0x%" PRIx64
" (end : 0x%" PRIx64
")\n",
233 FDE
->getAddressRange(),
234 FDE
->getInitialLocation() + FDE
->getAddressRange());
236 W
.getOStream() << "\n";
237 W
.startLine() << "Program:\n";
239 FDE
->cfis().dump(W
.getOStream(), nullptr, W
.getIndentLevel());
243 W
.getOStream() << "\n";
245 llvm_unreachable("unexpected DWARF frame kind");