xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h (revision c66ec88fed842fbaad62c30d510644ceb7bd2d71)
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   using Elf_Shdr = typename ELFT::Shdr;
34   using Elf_Phdr = typename ELFT::Phdr;
35 
36   ScopedPrinter &W;
37   const object::ELFObjectFile<ELFT> *ObjF;
38 
39   void printEHFrameHdr(const Elf_Phdr *EHFramePHdr) const;
40   void printEHFrame(const Elf_Shdr *EHFrameShdr) const;
41 
42 public:
43   PrinterContext(ScopedPrinter &W, const object::ELFObjectFile<ELFT> *ObjF)
44       : W(W), ObjF(ObjF) {}
45 
46   void printUnwindInformation() const;
47 };
48 
49 template <class ELFT>
50 static const typename ELFT::Shdr *
51 findSectionByAddress(const object::ELFObjectFile<ELFT> *ObjF, uint64_t Addr) {
52   Expected<typename ELFT::ShdrRange> SectionsOrErr =
53       ObjF->getELFFile()->sections();
54   if (!SectionsOrErr)
55     reportError(SectionsOrErr.takeError(), ObjF->getFileName());
56 
57   for (const typename ELFT::Shdr &Shdr : *SectionsOrErr)
58     if (Shdr.sh_addr == Addr)
59       return &Shdr;
60   return nullptr;
61 }
62 
63 template <typename ELFT>
64 void PrinterContext<ELFT>::printUnwindInformation() const {
65   const object::ELFFile<ELFT> *Obj = ObjF->getELFFile();
66 
67   Expected<typename ELFT::PhdrRange> PhdrsOrErr = Obj->program_headers();
68   if (!PhdrsOrErr)
69     reportError(PhdrsOrErr.takeError(), ObjF->getFileName());
70 
71   for (const Elf_Phdr &Phdr : *PhdrsOrErr) {
72     if (Phdr.p_type != ELF::PT_GNU_EH_FRAME)
73       continue;
74 
75     if (Phdr.p_memsz != Phdr.p_filesz)
76       reportError(object::createError(
77                       "p_memsz does not match p_filesz for GNU_EH_FRAME"),
78                   ObjF->getFileName());
79     printEHFrameHdr(&Phdr);
80     break;
81   }
82 
83   Expected<typename ELFT::ShdrRange> SectionsOrErr =
84       ObjF->getELFFile()->sections();
85   if (!SectionsOrErr)
86     reportError(SectionsOrErr.takeError(), ObjF->getFileName());
87 
88   for (const Elf_Shdr &Shdr : *SectionsOrErr) {
89     Expected<StringRef> NameOrErr = Obj->getSectionName(&Shdr);
90     if (!NameOrErr)
91       reportError(NameOrErr.takeError(), ObjF->getFileName());
92     if (*NameOrErr == ".eh_frame")
93       printEHFrame(&Shdr);
94   }
95 }
96 
97 template <typename ELFT>
98 void PrinterContext<ELFT>::printEHFrameHdr(const Elf_Phdr *EHFramePHdr) const {
99   DictScope L(W, "EHFrameHeader");
100   uint64_t EHFrameHdrAddress = EHFramePHdr->p_vaddr;
101   W.startLine() << format("Address: 0x%" PRIx64 "\n", EHFrameHdrAddress);
102   W.startLine() << format("Offset: 0x%" PRIx64 "\n", (uint64_t)EHFramePHdr->p_offset);
103   W.startLine() << format("Size: 0x%" PRIx64 "\n", (uint64_t)EHFramePHdr->p_memsz);
104 
105   const object::ELFFile<ELFT> *Obj = ObjF->getELFFile();
106   if (const Elf_Shdr *EHFrameHdr =
107           findSectionByAddress(ObjF, EHFramePHdr->p_vaddr)) {
108     Expected<StringRef> NameOrErr = Obj->getSectionName(EHFrameHdr);
109     if (!NameOrErr)
110       reportError(NameOrErr.takeError(), ObjF->getFileName());
111     W.printString("Corresponding Section", *NameOrErr);
112   }
113 
114   Expected<ArrayRef<uint8_t>> Content = Obj->getSegmentContents(EHFramePHdr);
115   if (!Content)
116     reportError(Content.takeError(), ObjF->getFileName());
117 
118   DataExtractor DE(*Content,
119                    ELFT::TargetEndianness == support::endianness::little,
120                    ELFT::Is64Bits ? 8 : 4);
121 
122   DictScope D(W, "Header");
123   uint64_t Offset = 0;
124 
125   auto Version = DE.getU8(&Offset);
126   W.printNumber("version", Version);
127   if (Version != 1)
128     reportError(
129         object::createError("only version 1 of .eh_frame_hdr is supported"),
130         ObjF->getFileName());
131 
132   uint64_t EHFramePtrEnc = DE.getU8(&Offset);
133   W.startLine() << format("eh_frame_ptr_enc: 0x%" PRIx64 "\n", EHFramePtrEnc);
134   if (EHFramePtrEnc != (dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4))
135     reportError(object::createError("unexpected encoding eh_frame_ptr_enc"),
136                 ObjF->getFileName());
137 
138   uint64_t FDECountEnc = DE.getU8(&Offset);
139   W.startLine() << format("fde_count_enc: 0x%" PRIx64 "\n", FDECountEnc);
140   if (FDECountEnc != dwarf::DW_EH_PE_udata4)
141     reportError(object::createError("unexpected encoding fde_count_enc"),
142                 ObjF->getFileName());
143 
144   uint64_t TableEnc = DE.getU8(&Offset);
145   W.startLine() << format("table_enc: 0x%" PRIx64 "\n", TableEnc);
146   if (TableEnc != (dwarf::DW_EH_PE_datarel | dwarf::DW_EH_PE_sdata4))
147     reportError(object::createError("unexpected encoding table_enc"),
148                 ObjF->getFileName());
149 
150   auto EHFramePtr = DE.getSigned(&Offset, 4) + EHFrameHdrAddress + 4;
151   W.startLine() << format("eh_frame_ptr: 0x%" PRIx64 "\n", EHFramePtr);
152 
153   auto FDECount = DE.getUnsigned(&Offset, 4);
154   W.printNumber("fde_count", FDECount);
155 
156   unsigned NumEntries = 0;
157   uint64_t PrevPC = 0;
158   while (Offset + 8 <= EHFramePHdr->p_memsz && NumEntries < FDECount) {
159     DictScope D(W, std::string("entry ")  + std::to_string(NumEntries));
160 
161     auto InitialPC = DE.getSigned(&Offset, 4) + EHFrameHdrAddress;
162     W.startLine() << format("initial_location: 0x%" PRIx64 "\n", InitialPC);
163     auto Address = DE.getSigned(&Offset, 4) + EHFrameHdrAddress;
164     W.startLine() << format("address: 0x%" PRIx64 "\n", Address);
165 
166     if (InitialPC < PrevPC)
167       reportError(object::createError("initial_location is out of order"),
168                   ObjF->getFileName());
169 
170     PrevPC = InitialPC;
171     ++NumEntries;
172   }
173 }
174 
175 template <typename ELFT>
176 void PrinterContext<ELFT>::printEHFrame(const Elf_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",
181                           ShOffset, Address);
182   W.indent();
183 
184   Expected<ArrayRef<uint8_t>> DataOrErr =
185       ObjF->getELFFile()->getSectionContents(EHFrameShdr);
186   if (!DataOrErr)
187     reportError(DataOrErr.takeError(), ObjF->getFileName());
188 
189   DWARFDataExtractor DE(*DataOrErr,
190                         ELFT::TargetEndianness == support::endianness::little,
191                         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());
196 
197   for (const dwarf::FrameEntry &Entry : EHFrame) {
198     if (const dwarf::CIE *CIE = dyn_cast<dwarf::CIE>(&Entry)) {
199       W.startLine() << format("[0x%" PRIx64 "] CIE length=%" PRIu64 "\n",
200                               Address + CIE->getOffset(), CIE->getLength());
201       W.indent();
202 
203       W.printNumber("version", CIE->getVersion());
204       W.printString("augmentation", CIE->getAugmentationString());
205       W.printNumber("code_alignment_factor", CIE->getCodeAlignmentFactor());
206       W.printNumber("data_alignment_factor", CIE->getDataAlignmentFactor());
207       W.printNumber("return_address_register", CIE->getReturnAddressRegister());
208     } else {
209       const dwarf::FDE *FDE = cast<dwarf::FDE>(&Entry);
210       W.startLine() << format("[0x%" PRIx64 "] FDE length=%" PRIu64
211                               " cie=[0x%" PRIx64 "]\n",
212                               Address + FDE->getOffset(), FDE->getLength(),
213                               Address + FDE->getLinkedCIE()->getOffset());
214       W.indent();
215 
216       W.startLine() << format("initial_location: 0x%" PRIx64 "\n",
217                               FDE->getInitialLocation());
218       W.startLine() << format(
219           "address_range: 0x%" PRIx64 " (end : 0x%" PRIx64 ")\n",
220           FDE->getAddressRange(),
221           FDE->getInitialLocation() + FDE->getAddressRange());
222     }
223 
224     W.getOStream() << "\n";
225     W.startLine() << "Program:\n";
226     W.indent();
227     Entry.cfis().dump(W.getOStream(), nullptr, W.getIndentLevel());
228     W.unindent();
229     W.unindent();
230     W.getOStream() << "\n";
231   }
232 
233   W.unindent();
234 }
235 }
236 }
237 
238 #endif
239