[sanitizer] Improve FreeBSD ASLR detection
[llvm-project.git] / llvm / tools / llvm-readobj / DwarfCFIEHPrinter.h
blob5dc947e024b92e83ede8b37314333700f1d6914c
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 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_TOOLS_LLVM_READOBJ_DWARFCFIEHPRINTER_H
10 #define LLVM_TOOLS_LLVM_READOBJ_DWARFCFIEHPRINTER_H
12 #include "llvm-readobj.h"
13 #include "llvm/ADT/STLExtras.h"
14 #include "llvm/BinaryFormat/Dwarf.h"
15 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
16 #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
17 #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
18 #include "llvm/Object/ELF.h"
19 #include "llvm/Object/ELFObjectFile.h"
20 #include "llvm/Object/ELFTypes.h"
21 #include "llvm/Support/Casting.h"
22 #include "llvm/Support/Debug.h"
23 #include "llvm/Support/Endian.h"
24 #include "llvm/Support/Format.h"
25 #include "llvm/Support/ScopedPrinter.h"
26 #include "llvm/Support/type_traits.h"
28 namespace llvm {
29 namespace DwarfCFIEH {
31 template <typename ELFT> class PrinterContext {
32 using Elf_Shdr = typename ELFT::Shdr;
33 using Elf_Phdr = typename ELFT::Phdr;
35 ScopedPrinter &W;
36 const object::ELFObjectFile<ELFT> &ObjF;
38 void printEHFrameHdr(const Elf_Phdr *EHFramePHdr) const;
39 void printEHFrame(const Elf_Shdr *EHFrameShdr) const;
41 public:
42 PrinterContext(ScopedPrinter &W, const object::ELFObjectFile<ELFT> &ObjF)
43 : W(W), ObjF(ObjF) {}
45 void printUnwindInformation() const;
48 template <class ELFT>
49 static const typename ELFT::Shdr *
50 findSectionByAddress(const object::ELFObjectFile<ELFT> &ObjF, uint64_t Addr) {
51 Expected<typename ELFT::ShdrRange> SectionsOrErr =
52 ObjF.getELFFile().sections();
53 if (!SectionsOrErr)
54 reportError(SectionsOrErr.takeError(), ObjF.getFileName());
56 for (const typename ELFT::Shdr &Shdr : *SectionsOrErr)
57 if (Shdr.sh_addr == Addr)
58 return &Shdr;
59 return nullptr;
62 template <typename ELFT>
63 void PrinterContext<ELFT>::printUnwindInformation() const {
64 const object::ELFFile<ELFT> &Obj = ObjF.getELFFile();
66 Expected<typename ELFT::PhdrRange> PhdrsOrErr = Obj.program_headers();
67 if (!PhdrsOrErr)
68 reportError(PhdrsOrErr.takeError(), ObjF.getFileName());
70 for (const Elf_Phdr &Phdr : *PhdrsOrErr) {
71 if (Phdr.p_type != ELF::PT_GNU_EH_FRAME)
72 continue;
74 if (Phdr.p_memsz != Phdr.p_filesz)
75 reportError(object::createError(
76 "p_memsz does not match p_filesz for GNU_EH_FRAME"),
77 ObjF.getFileName());
78 printEHFrameHdr(&Phdr);
79 break;
82 Expected<typename ELFT::ShdrRange> SectionsOrErr = Obj.sections();
83 if (!SectionsOrErr)
84 reportError(SectionsOrErr.takeError(), ObjF.getFileName());
86 for (const Elf_Shdr &Shdr : *SectionsOrErr) {
87 Expected<StringRef> NameOrErr = Obj.getSectionName(Shdr);
88 if (!NameOrErr)
89 reportError(NameOrErr.takeError(), ObjF.getFileName());
90 if (*NameOrErr == ".eh_frame")
91 printEHFrame(&Shdr);
95 template <typename ELFT>
96 void PrinterContext<ELFT>::printEHFrameHdr(const Elf_Phdr *EHFramePHdr) const {
97 DictScope L(W, "EHFrameHeader");
98 uint64_t EHFrameHdrAddress = EHFramePHdr->p_vaddr;
99 W.startLine() << format("Address: 0x%" PRIx64 "\n", EHFrameHdrAddress);
100 W.startLine() << format("Offset: 0x%" PRIx64 "\n", (uint64_t)EHFramePHdr->p_offset);
101 W.startLine() << format("Size: 0x%" PRIx64 "\n", (uint64_t)EHFramePHdr->p_memsz);
103 const object::ELFFile<ELFT> &Obj = ObjF.getELFFile();
104 if (const Elf_Shdr *EHFrameHdr =
105 findSectionByAddress(ObjF, EHFramePHdr->p_vaddr)) {
106 Expected<StringRef> NameOrErr = Obj.getSectionName(*EHFrameHdr);
107 if (!NameOrErr)
108 reportError(NameOrErr.takeError(), ObjF.getFileName());
109 W.printString("Corresponding Section", *NameOrErr);
112 Expected<ArrayRef<uint8_t>> Content = Obj.getSegmentContents(*EHFramePHdr);
113 if (!Content)
114 reportError(Content.takeError(), ObjF.getFileName());
116 DataExtractor DE(*Content,
117 ELFT::TargetEndianness == support::endianness::little,
118 ELFT::Is64Bits ? 8 : 4);
120 DictScope D(W, "Header");
121 uint64_t Offset = 0;
123 auto Version = DE.getU8(&Offset);
124 W.printNumber("version", Version);
125 if (Version != 1)
126 reportError(
127 object::createError("only version 1 of .eh_frame_hdr is supported"),
128 ObjF.getFileName());
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(object::createError("unexpected encoding eh_frame_ptr_enc"),
134 ObjF.getFileName());
136 uint64_t FDECountEnc = DE.getU8(&Offset);
137 W.startLine() << format("fde_count_enc: 0x%" PRIx64 "\n", FDECountEnc);
138 if (FDECountEnc != dwarf::DW_EH_PE_udata4)
139 reportError(object::createError("unexpected encoding fde_count_enc"),
140 ObjF.getFileName());
142 uint64_t TableEnc = DE.getU8(&Offset);
143 W.startLine() << format("table_enc: 0x%" PRIx64 "\n", TableEnc);
144 if (TableEnc != (dwarf::DW_EH_PE_datarel | dwarf::DW_EH_PE_sdata4))
145 reportError(object::createError("unexpected encoding table_enc"),
146 ObjF.getFileName());
148 auto EHFramePtr = DE.getSigned(&Offset, 4) + EHFrameHdrAddress + 4;
149 W.startLine() << format("eh_frame_ptr: 0x%" PRIx64 "\n", EHFramePtr);
151 auto FDECount = DE.getUnsigned(&Offset, 4);
152 W.printNumber("fde_count", FDECount);
154 unsigned NumEntries = 0;
155 uint64_t PrevPC = 0;
156 while (Offset + 8 <= EHFramePHdr->p_memsz && NumEntries < FDECount) {
157 DictScope D(W, std::string("entry ") + std::to_string(NumEntries));
159 auto InitialPC = DE.getSigned(&Offset, 4) + EHFrameHdrAddress;
160 W.startLine() << format("initial_location: 0x%" PRIx64 "\n", InitialPC);
161 auto Address = DE.getSigned(&Offset, 4) + EHFrameHdrAddress;
162 W.startLine() << format("address: 0x%" PRIx64 "\n", Address);
164 if (InitialPC < PrevPC)
165 reportError(object::createError("initial_location is out of order"),
166 ObjF.getFileName());
168 PrevPC = InitialPC;
169 ++NumEntries;
173 template <typename ELFT>
174 void PrinterContext<ELFT>::printEHFrame(const Elf_Shdr *EHFrameShdr) const {
175 uint64_t Address = EHFrameShdr->sh_addr;
176 uint64_t ShOffset = EHFrameShdr->sh_offset;
177 W.startLine() << format(".eh_frame section at offset 0x%" PRIx64
178 " address 0x%" PRIx64 ":\n",
179 ShOffset, Address);
180 W.indent();
182 Expected<ArrayRef<uint8_t>> DataOrErr =
183 ObjF.getELFFile().getSectionContents(*EHFrameShdr);
184 if (!DataOrErr)
185 reportError(DataOrErr.takeError(), ObjF.getFileName());
187 // Construct DWARFDataExtractor to handle relocations ("PC Begin" fields).
188 std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(
189 ObjF, DWARFContext::ProcessDebugRelocations::Process, nullptr);
190 DWARFDataExtractor DE(DICtx->getDWARFObj(),
191 DICtx->getDWARFObj().getEHFrameSection(),
192 ELFT::TargetEndianness == support::endianness::little,
193 ELFT::Is64Bits ? 8 : 4);
194 DWARFDebugFrame EHFrame(Triple::ArchType(ObjF.getArch()), /*IsEH=*/true,
195 /*EHFrameAddress=*/Address);
196 if (Error E = EHFrame.parse(DE))
197 reportError(std::move(E), ObjF.getFileName());
199 for (const dwarf::FrameEntry &Entry : EHFrame) {
200 if (const dwarf::CIE *CIE = dyn_cast<dwarf::CIE>(&Entry)) {
201 W.startLine() << format("[0x%" PRIx64 "] CIE length=%" PRIu64 "\n",
202 Address + CIE->getOffset(), CIE->getLength());
203 W.indent();
205 W.printNumber("version", CIE->getVersion());
206 W.printString("augmentation", CIE->getAugmentationString());
207 W.printNumber("code_alignment_factor", CIE->getCodeAlignmentFactor());
208 W.printNumber("data_alignment_factor", CIE->getDataAlignmentFactor());
209 W.printNumber("return_address_register", CIE->getReturnAddressRegister());
210 } else {
211 const dwarf::FDE *FDE = cast<dwarf::FDE>(&Entry);
212 W.startLine() << format("[0x%" PRIx64 "] FDE length=%" PRIu64
213 " cie=[0x%" PRIx64 "]\n",
214 Address + FDE->getOffset(), FDE->getLength(),
215 Address + FDE->getLinkedCIE()->getOffset());
216 W.indent();
218 W.startLine() << format("initial_location: 0x%" PRIx64 "\n",
219 FDE->getInitialLocation());
220 W.startLine() << format(
221 "address_range: 0x%" PRIx64 " (end : 0x%" PRIx64 ")\n",
222 FDE->getAddressRange(),
223 FDE->getInitialLocation() + FDE->getAddressRange());
226 W.getOStream() << "\n";
227 W.startLine() << "Program:\n";
228 W.indent();
229 Entry.cfis().dump(W.getOStream(), DIDumpOptions(), nullptr,
230 W.getIndentLevel());
231 W.unindent();
232 W.unindent();
233 W.getOStream() << "\n";
236 W.unindent();
238 } // namespace DwarfCFIEH
239 } // namespace llvm
241 #endif