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