147
|
1 //===--- DwarfCFIEHPrinter.h - DWARF-based Unwind Information Printer -----===//
|
|
2 //
|
|
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
|
|
6 //
|
|
7 //===----------------------------------------------------------------------===//
|
|
8
|
|
9 #ifndef LLVM_TOOLS_LLVM_READOBJ_DWARFCFIEHPRINTER_H
|
|
10 #define LLVM_TOOLS_LLVM_READOBJ_DWARFCFIEHPRINTER_H
|
|
11
|
|
12 #include "Error.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"
|
|
27
|
|
28 namespace llvm {
|
|
29 namespace DwarfCFIEH {
|
|
30
|
|
31 template <typename ELFT>
|
|
32 class PrinterContext {
|
|
33 ScopedPrinter &W;
|
|
34 const object::ELFObjectFile<ELFT> *ObjF;
|
|
35
|
|
36 void printEHFrameHdr(uint64_t Offset, uint64_t Address, uint64_t Size) const;
|
|
37
|
|
38 void printEHFrame(const typename ELFT::Shdr *EHFrameShdr) const;
|
|
39
|
|
40 public:
|
|
41 PrinterContext(ScopedPrinter &W, const object::ELFObjectFile<ELFT> *ObjF)
|
|
42 : W(W), ObjF(ObjF) {}
|
|
43
|
|
44 void printUnwindInformation() const;
|
|
45 };
|
|
46
|
|
47 template <class ELFO>
|
|
48 static const typename ELFO::Elf_Shdr *findSectionByAddress(const ELFO *Obj,
|
|
49 uint64_t Addr) {
|
|
50 auto Sections = Obj->sections();
|
|
51 if (Error E = Sections.takeError())
|
|
52 reportError(toString(std::move(E)));
|
|
53
|
|
54 for (const auto &Shdr : *Sections)
|
|
55 if (Shdr.sh_addr == Addr)
|
|
56 return &Shdr;
|
|
57 return nullptr;
|
|
58 }
|
|
59
|
|
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;
|
|
64
|
|
65 auto PHs = Obj->program_headers();
|
|
66 if (Error E = PHs.takeError())
|
|
67 reportError(toString(std::move(E)));
|
|
68
|
|
69 for (const auto &Phdr : *PHs) {
|
|
70 if (Phdr.p_type == ELF::PT_GNU_EH_FRAME) {
|
|
71 EHFramePhdr = &Phdr;
|
|
72 if (Phdr.p_memsz != Phdr.p_filesz)
|
|
73 reportError("p_memsz does not match p_filesz for GNU_EH_FRAME");
|
|
74 break;
|
|
75 }
|
|
76 }
|
|
77
|
|
78 if (EHFramePhdr)
|
|
79 printEHFrameHdr(EHFramePhdr->p_offset, EHFramePhdr->p_vaddr,
|
|
80 EHFramePhdr->p_memsz);
|
|
81
|
|
82 auto Sections = Obj->sections();
|
|
83 if (Error E = Sections.takeError())
|
|
84 reportError(toString(std::move(E)));
|
|
85
|
|
86 for (const auto &Shdr : *Sections) {
|
|
87 auto SectionName = Obj->getSectionName(&Shdr);
|
|
88 if (Error E = SectionName.takeError())
|
|
89 reportError(toString(std::move(E)));
|
|
90
|
|
91 if (*SectionName == ".eh_frame")
|
|
92 printEHFrame(&Shdr);
|
|
93 }
|
|
94 }
|
|
95
|
|
96 template <typename ELFT>
|
|
97 void PrinterContext<ELFT>::printEHFrameHdr(uint64_t EHFrameHdrOffset,
|
|
98 uint64_t EHFrameHdrAddress,
|
|
99 uint64_t EHFrameHdrSize) const {
|
|
100 ListScope L(W, "EH_FRAME Header");
|
|
101 W.startLine() << format("Address: 0x%" PRIx64 "\n", EHFrameHdrAddress);
|
|
102 W.startLine() << format("Offset: 0x%" PRIx64 "\n", EHFrameHdrOffset);
|
|
103 W.startLine() << format("Size: 0x%" PRIx64 "\n", EHFrameHdrSize);
|
|
104
|
|
105 const object::ELFFile<ELFT> *Obj = ObjF->getELFFile();
|
|
106 const auto *EHFrameHdrShdr = findSectionByAddress(Obj, EHFrameHdrAddress);
|
|
107 if (EHFrameHdrShdr) {
|
|
108 auto SectionName = Obj->getSectionName(EHFrameHdrShdr);
|
|
109 if (Error E = SectionName.takeError())
|
|
110 reportError(toString(std::move(E)));
|
|
111
|
|
112 W.printString("Corresponding Section", *SectionName);
|
|
113 }
|
|
114
|
|
115 DataExtractor DE(
|
|
116 StringRef(reinterpret_cast<const char *>(Obj->base()) + EHFrameHdrOffset,
|
|
117 EHFrameHdrSize),
|
|
118 ELFT::TargetEndianness == support::endianness::little,
|
|
119 ELFT::Is64Bits ? 8 : 4);
|
|
120
|
|
121 DictScope D(W, "Header");
|
|
122 uint64_t Offset = 0;
|
|
123
|
|
124 auto Version = DE.getU8(&Offset);
|
|
125 W.printNumber("version", Version);
|
|
126 if (Version != 1)
|
|
127 reportError("only version 1 of .eh_frame_hdr is supported");
|
|
128
|
|
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("unexpected encoding eh_frame_ptr_enc");
|
|
133
|
|
134 uint64_t FDECountEnc = DE.getU8(&Offset);
|
|
135 W.startLine() << format("fde_count_enc: 0x%" PRIx64 "\n", FDECountEnc);
|
|
136 if (FDECountEnc != dwarf::DW_EH_PE_udata4)
|
|
137 reportError("unexpected encoding fde_count_enc");
|
|
138
|
|
139 uint64_t TableEnc = DE.getU8(&Offset);
|
|
140 W.startLine() << format("table_enc: 0x%" PRIx64 "\n", TableEnc);
|
|
141 if (TableEnc != (dwarf::DW_EH_PE_datarel | dwarf::DW_EH_PE_sdata4))
|
|
142 reportError("unexpected encoding table_enc");
|
|
143
|
|
144 auto EHFramePtr = DE.getSigned(&Offset, 4) + EHFrameHdrAddress + 4;
|
|
145 W.startLine() << format("eh_frame_ptr: 0x%" PRIx64 "\n", EHFramePtr);
|
|
146
|
|
147 auto FDECount = DE.getUnsigned(&Offset, 4);
|
|
148 W.printNumber("fde_count", FDECount);
|
|
149
|
|
150 unsigned NumEntries = 0;
|
|
151 uint64_t PrevPC = 0;
|
|
152 while (Offset + 8 <= EHFrameHdrSize && NumEntries < FDECount) {
|
|
153 DictScope D(W, std::string("entry ") + std::to_string(NumEntries));
|
|
154
|
|
155 auto InitialPC = DE.getSigned(&Offset, 4) + EHFrameHdrAddress;
|
|
156 W.startLine() << format("initial_location: 0x%" PRIx64 "\n", InitialPC);
|
|
157 auto Address = DE.getSigned(&Offset, 4) + EHFrameHdrAddress;
|
|
158 W.startLine() << format("address: 0x%" PRIx64 "\n", Address);
|
|
159
|
|
160 if (InitialPC < PrevPC)
|
|
161 reportError("initial_location is out of order");
|
|
162
|
|
163 PrevPC = InitialPC;
|
|
164 ++NumEntries;
|
|
165 }
|
|
166 }
|
|
167
|
|
168 template <typename ELFT>
|
|
169 void PrinterContext<ELFT>::printEHFrame(
|
|
170 const typename ELFT::Shdr *EHFrameShdr) const {
|
|
171 uint64_t Address = EHFrameShdr->sh_addr;
|
|
172 uint64_t ShOffset = EHFrameShdr->sh_offset;
|
|
173 W.startLine() << format(".eh_frame section at offset 0x%" PRIx64
|
|
174 " address 0x%" PRIx64 ":\n",
|
|
175 ShOffset, Address);
|
|
176 W.indent();
|
|
177
|
|
178 const object::ELFFile<ELFT> *Obj = ObjF->getELFFile();
|
|
179 auto Result = Obj->getSectionContents(EHFrameShdr);
|
|
180 if (Error E = Result.takeError())
|
|
181 reportError(toString(std::move(E)));
|
|
182
|
|
183 auto Contents = Result.get();
|
|
184 DWARFDataExtractor DE(
|
|
185 StringRef(reinterpret_cast<const char *>(Contents.data()),
|
|
186 Contents.size()),
|
|
187 ELFT::TargetEndianness == support::endianness::little,
|
|
188 ELFT::Is64Bits ? 8 : 4);
|
|
189 DWARFDebugFrame EHFrame(Triple::ArchType(ObjF->getArch()), /*IsEH=*/true,
|
|
190 /*EHFrameAddress=*/Address);
|
|
191 EHFrame.parse(DE);
|
|
192
|
|
193 for (const auto &Entry : EHFrame) {
|
|
194 if (const auto *CIE = dyn_cast<dwarf::CIE>(&Entry)) {
|
|
195 W.startLine() << format("[0x%" PRIx64 "] CIE length=%" PRIu64 "\n",
|
|
196 Address + CIE->getOffset(),
|
|
197 CIE->getLength());
|
|
198 W.indent();
|
|
199
|
|
200 W.printNumber("version", CIE->getVersion());
|
|
201 W.printString("augmentation", CIE->getAugmentationString());
|
|
202 W.printNumber("code_alignment_factor", CIE->getCodeAlignmentFactor());
|
|
203 W.printNumber("data_alignment_factor", CIE->getDataAlignmentFactor());
|
|
204 W.printNumber("return_address_register", CIE->getReturnAddressRegister());
|
|
205
|
|
206 W.getOStream() << "\n";
|
|
207 W.startLine() << "Program:\n";
|
|
208 W.indent();
|
|
209 CIE->cfis().dump(W.getOStream(), nullptr, W.getIndentLevel());
|
|
210 W.unindent();
|
|
211
|
|
212 W.unindent();
|
|
213 W.getOStream() << "\n";
|
|
214
|
|
215 } else if (const auto *FDE = dyn_cast<dwarf::FDE>(&Entry)) {
|
|
216 W.startLine() << format("[0x%" PRIx64 "] FDE length=%" PRIu64
|
|
217 " cie=[0x%" PRIx64 "]\n",
|
|
218 Address + FDE->getOffset(),
|
|
219 FDE->getLength(),
|
|
220 Address + FDE->getLinkedCIE()->getOffset());
|
|
221 W.indent();
|
|
222
|
|
223 W.startLine() << format("initial_location: 0x%" PRIx64 "\n",
|
|
224 FDE->getInitialLocation());
|
|
225 W.startLine()
|
|
226 << format("address_range: 0x%" PRIx64 " (end : 0x%" PRIx64 ")\n",
|
|
227 FDE->getAddressRange(),
|
|
228 FDE->getInitialLocation() + FDE->getAddressRange());
|
|
229
|
|
230 W.getOStream() << "\n";
|
|
231 W.startLine() << "Program:\n";
|
|
232 W.indent();
|
|
233 FDE->cfis().dump(W.getOStream(), nullptr, W.getIndentLevel());
|
|
234 W.unindent();
|
|
235
|
|
236 W.unindent();
|
|
237 W.getOStream() << "\n";
|
|
238 } else {
|
|
239 llvm_unreachable("unexpected DWARF frame kind");
|
|
240 }
|
|
241 }
|
|
242
|
|
243 W.unindent();
|
|
244 }
|
|
245
|
|
246 }
|
|
247 }
|
|
248
|
|
249 #endif
|