]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h
Merge clang 7.0.1 and several follow-up changes
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / llvm-readobj / DwarfCFIEHPrinter.h
1 //===--- DwarfCFIEHPrinter.h - DWARF-based Unwind Information Printer -----===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #ifndef LLVM_TOOLS_LLVM_READOBJ_DWARFCFIEHPRINTER_H
11 #define LLVM_TOOLS_LLVM_READOBJ_DWARFCFIEHPRINTER_H
12
13 #include "Error.h"
14 #include "llvm-readobj.h"
15 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/BinaryFormat/Dwarf.h"
17 #include "llvm/Object/ELF.h"
18 #include "llvm/Object/ELFTypes.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::ELFFile<ELFT> *Obj;
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::ELFFile<ELFT> *Obj)
42       : W(W), Obj(Obj) {}
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 typename ELFT::Phdr *EHFramePhdr = nullptr;
63
64   auto PHs = Obj->program_headers();
65   if (Error E = PHs.takeError())
66     reportError(toString(std::move(E)));
67
68   for (const auto &Phdr : *PHs) {
69     if (Phdr.p_type == ELF::PT_GNU_EH_FRAME) {
70       EHFramePhdr = &Phdr;
71       if (Phdr.p_memsz != Phdr.p_filesz)
72         reportError("p_memsz does not match p_filesz for GNU_EH_FRAME");
73       break;
74     }
75   }
76
77   if (EHFramePhdr)
78     printEHFrameHdr(EHFramePhdr->p_offset, EHFramePhdr->p_vaddr,
79                     EHFramePhdr->p_memsz);
80
81   auto Sections = Obj->sections();
82   if (Error E = Sections.takeError())
83     reportError(toString(std::move(E)));
84
85   for (const auto &Shdr : *Sections) {
86     auto SectionName = Obj->getSectionName(&Shdr);
87     if (Error E = SectionName.takeError())
88       reportError(toString(std::move(E)));
89
90     if (*SectionName == ".eh_frame")
91       printEHFrame(&Shdr);
92   }
93 }
94
95 template <typename ELFT>
96 void PrinterContext<ELFT>::printEHFrameHdr(uint64_t EHFrameHdrOffset,
97                                            uint64_t EHFrameHdrAddress,
98                                            uint64_t EHFrameHdrSize) const {
99   ListScope L(W, "EH_FRAME Header");
100   W.startLine() << format("Address: 0x%" PRIx64 "\n", EHFrameHdrAddress);
101   W.startLine() << format("Offset: 0x%" PRIx64 "\n", EHFrameHdrOffset);
102   W.startLine() << format("Size: 0x%" PRIx64 "\n", EHFrameHdrSize);
103
104   const auto *EHFrameHdrShdr = findSectionByAddress(Obj, EHFrameHdrAddress);
105   if (EHFrameHdrShdr) {
106     auto SectionName = Obj->getSectionName(EHFrameHdrShdr);
107     if (Error E = SectionName.takeError())
108       reportError(toString(std::move(E)));
109
110     W.printString("Corresponding Section", *SectionName);
111   }
112
113   DataExtractor DE(
114       StringRef(reinterpret_cast<const char *>(Obj->base()) + EHFrameHdrOffset,
115                 EHFrameHdrSize),
116       ELFT::TargetEndianness == support::endianness::little,
117       ELFT::Is64Bits ? 8 : 4);
118
119   DictScope D(W, "Header");
120   uint32_t Offset = 0;
121
122   auto Version = DE.getU8(&Offset);
123   W.printNumber("version", Version);
124   if (Version != 1)
125     reportError("only version 1 of .eh_frame_hdr is supported");
126
127   uint64_t EHFramePtrEnc = DE.getU8(&Offset);
128   W.startLine() << format("eh_frame_ptr_enc: 0x%" PRIx64 "\n", EHFramePtrEnc);
129   if (EHFramePtrEnc != (dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4))
130     reportError("unexpected encoding eh_frame_ptr_enc");
131
132   uint64_t FDECountEnc = DE.getU8(&Offset);
133   W.startLine() << format("fde_count_enc: 0x%" PRIx64 "\n", FDECountEnc);
134   if (FDECountEnc != dwarf::DW_EH_PE_udata4)
135     reportError("unexpected encoding fde_count_enc");
136
137   uint64_t TableEnc = DE.getU8(&Offset);
138   W.startLine() << format("table_enc: 0x%" PRIx64 "\n", TableEnc);
139   if (TableEnc != (dwarf::DW_EH_PE_datarel | dwarf::DW_EH_PE_sdata4))
140     reportError("unexpected encoding table_enc");
141
142   auto EHFramePtr = DE.getSigned(&Offset, 4) + EHFrameHdrAddress + 4;
143   W.startLine() << format("eh_frame_ptr: 0x%" PRIx64 "\n", EHFramePtr);
144
145   auto FDECount = DE.getUnsigned(&Offset, 4);
146   W.printNumber("fde_count", FDECount);
147
148   unsigned NumEntries = 0;
149   uint64_t PrevPC = 0;
150   while (Offset + 8 <= EHFrameHdrSize && NumEntries < FDECount) {
151     DictScope D(W, std::string("entry ")  + std::to_string(NumEntries));
152
153     auto InitialPC = DE.getSigned(&Offset, 4) + EHFrameHdrAddress;
154     W.startLine() << format("initial_location: 0x%" PRIx64 "\n", InitialPC);
155     auto Address = DE.getSigned(&Offset, 4) + EHFrameHdrAddress;
156     W.startLine() << format("address: 0x%" PRIx64 "\n", Address);
157
158     if (InitialPC < PrevPC)
159       reportError("initial_location is out of order");
160
161     PrevPC = InitialPC;
162     ++NumEntries;
163   }
164 }
165
166 template <typename ELFT>
167 void PrinterContext<ELFT>::printEHFrame(
168     const typename ELFT::Shdr *EHFrameShdr) const {
169   uint64_t Address = EHFrameShdr->sh_addr;
170   uint64_t ShOffset = EHFrameShdr->sh_offset;
171   W.startLine() << format(".eh_frame section at offset 0x%" PRIx64
172                           " address 0x%" PRIx64 ":\n",
173                           ShOffset, Address);
174   W.indent();
175
176   auto Result = Obj->getSectionContents(EHFrameShdr);
177   if (Error E = Result.takeError())
178     reportError(toString(std::move(E)));
179
180   auto Contents = Result.get();
181   DWARFDataExtractor DE(
182       StringRef(reinterpret_cast<const char *>(Contents.data()),
183                 Contents.size()),
184       ELFT::TargetEndianness == support::endianness::little,
185       ELFT::Is64Bits ? 8 : 4);
186   DWARFDebugFrame EHFrame(/*IsEH=*/true, /*EHFrameAddress=*/Address);
187   EHFrame.parse(DE);
188
189   for (const auto &Entry : EHFrame) {
190     if (const auto *CIE = dyn_cast<dwarf::CIE>(&Entry)) {
191       W.startLine() << format("[0x%" PRIx64 "] CIE length=%" PRIu64 "\n",
192                               Address + CIE->getOffset(),
193                               CIE->getLength());
194       W.indent();
195
196       W.printNumber("version", CIE->getVersion());
197       W.printString("augmentation", CIE->getAugmentationString());
198       W.printNumber("code_alignment_factor", CIE->getCodeAlignmentFactor());
199       W.printNumber("data_alignment_factor", CIE->getDataAlignmentFactor());
200       W.printNumber("return_address_register", CIE->getReturnAddressRegister());
201
202       W.getOStream() << "\n";
203       W.startLine() << "Program:\n";
204       W.indent();
205       CIE->cfis().dump(W.getOStream(), nullptr, W.getIndentLevel());
206       W.unindent();
207
208       W.unindent();
209       W.getOStream() << "\n";
210
211     } else if (const auto *FDE = dyn_cast<dwarf::FDE>(&Entry)) {
212       W.startLine() << format("[0x%" PRIx64 "] FDE length=%" PRIu64
213                               " cie=[0x%" PRIx64 "]\n",
214                               Address + FDE->getOffset(),
215                               FDE->getLength(),
216                               Address + FDE->getLinkedCIE()->getOffset());
217       W.indent();
218
219       W.startLine() << format("initial_location: 0x%" PRIx64 "\n",
220                               FDE->getInitialLocation());
221       W.startLine()
222         << format("address_range: 0x%" PRIx64 " (end : 0x%" PRIx64 ")\n",
223                   FDE->getAddressRange(),
224                   FDE->getInitialLocation() + FDE->getAddressRange());
225
226       W.getOStream() << "\n";
227       W.startLine() << "Program:\n";
228       W.indent();
229       FDE->cfis().dump(W.getOStream(), nullptr, W.getIndentLevel());
230       W.unindent();
231
232       W.unindent();
233       W.getOStream() << "\n";
234     } else {
235       llvm_unreachable("unexpected DWARF frame kind");
236     }
237   }
238
239   W.unindent();
240 }
241
242 }
243 }
244
245 #endif