Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h
35230 views
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 "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"
27
28
namespace llvm {
29
namespace DwarfCFIEH {
30
31
template <typename ELFT> class PrinterContext {
32
using Elf_Shdr = typename ELFT::Shdr;
33
using Elf_Phdr = typename ELFT::Phdr;
34
35
ScopedPrinter &W;
36
const object::ELFObjectFile<ELFT> &ObjF;
37
38
void printEHFrameHdr(const Elf_Phdr *EHFramePHdr) const;
39
void printEHFrame(const Elf_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 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());
55
56
for (const typename ELFT::Shdr &Shdr : *SectionsOrErr)
57
if (Shdr.sh_addr == Addr)
58
return &Shdr;
59
return nullptr;
60
}
61
62
template <typename ELFT>
63
void PrinterContext<ELFT>::printUnwindInformation() const {
64
const object::ELFFile<ELFT> &Obj = ObjF.getELFFile();
65
66
Expected<typename ELFT::PhdrRange> PhdrsOrErr = Obj.program_headers();
67
if (!PhdrsOrErr)
68
reportError(PhdrsOrErr.takeError(), ObjF.getFileName());
69
70
for (const Elf_Phdr &Phdr : *PhdrsOrErr) {
71
if (Phdr.p_type != ELF::PT_GNU_EH_FRAME)
72
continue;
73
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;
80
}
81
82
Expected<typename ELFT::ShdrRange> SectionsOrErr = Obj.sections();
83
if (!SectionsOrErr)
84
reportError(SectionsOrErr.takeError(), ObjF.getFileName());
85
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);
92
}
93
}
94
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);
102
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);
110
}
111
112
Expected<ArrayRef<uint8_t>> Content = Obj.getSegmentContents(*EHFramePHdr);
113
if (!Content)
114
reportError(Content.takeError(), ObjF.getFileName());
115
116
DataExtractor DE(*Content, ELFT::Endianness == llvm::endianness::little,
117
ELFT::Is64Bits ? 8 : 4);
118
119
DictScope D(W, "Header");
120
uint64_t Offset = 0;
121
122
auto Version = DE.getU8(&Offset);
123
W.printNumber("version", Version);
124
if (Version != 1)
125
reportError(
126
object::createError("only version 1 of .eh_frame_hdr is supported"),
127
ObjF.getFileName());
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(object::createError("unexpected encoding eh_frame_ptr_enc"),
133
ObjF.getFileName());
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(object::createError("unexpected encoding fde_count_enc"),
139
ObjF.getFileName());
140
141
uint64_t TableEnc = DE.getU8(&Offset);
142
W.startLine() << format("table_enc: 0x%" PRIx64 "\n", TableEnc);
143
if (TableEnc != (dwarf::DW_EH_PE_datarel | dwarf::DW_EH_PE_sdata4))
144
reportError(object::createError("unexpected encoding table_enc"),
145
ObjF.getFileName());
146
147
auto EHFramePtr = DE.getSigned(&Offset, 4) + EHFrameHdrAddress + 4;
148
W.startLine() << format("eh_frame_ptr: 0x%" PRIx64 "\n", EHFramePtr);
149
150
auto FDECount = DE.getUnsigned(&Offset, 4);
151
W.printNumber("fde_count", FDECount);
152
153
unsigned NumEntries = 0;
154
uint64_t PrevPC = 0;
155
while (Offset + 8 <= EHFramePHdr->p_memsz && NumEntries < FDECount) {
156
DictScope D(W, std::string("entry ") + std::to_string(NumEntries));
157
158
auto InitialPC = DE.getSigned(&Offset, 4) + EHFrameHdrAddress;
159
W.startLine() << format("initial_location: 0x%" PRIx64 "\n", InitialPC);
160
auto Address = DE.getSigned(&Offset, 4) + EHFrameHdrAddress;
161
W.startLine() << format("address: 0x%" PRIx64 "\n", Address);
162
163
if (InitialPC < PrevPC)
164
reportError(object::createError("initial_location is out of order"),
165
ObjF.getFileName());
166
167
PrevPC = InitialPC;
168
++NumEntries;
169
}
170
}
171
172
template <typename ELFT>
173
void PrinterContext<ELFT>::printEHFrame(const Elf_Shdr *EHFrameShdr) const {
174
uint64_t Address = EHFrameShdr->sh_addr;
175
uint64_t ShOffset = EHFrameShdr->sh_offset;
176
W.startLine() << format(".eh_frame section at offset 0x%" PRIx64
177
" address 0x%" PRIx64 ":\n",
178
ShOffset, Address);
179
W.indent();
180
181
Expected<ArrayRef<uint8_t>> DataOrErr =
182
ObjF.getELFFile().getSectionContents(*EHFrameShdr);
183
if (!DataOrErr)
184
reportError(DataOrErr.takeError(), ObjF.getFileName());
185
186
// Construct DWARFDataExtractor to handle relocations ("PC Begin" fields).
187
std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(
188
ObjF, DWARFContext::ProcessDebugRelocations::Process, nullptr);
189
DWARFDataExtractor DE(
190
DICtx->getDWARFObj(), DICtx->getDWARFObj().getEHFrameSection(),
191
ELFT::Endianness == llvm::endianness::little, 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
std::optional<uint64_t> InitialLocation;
199
if (const dwarf::CIE *CIE = dyn_cast<dwarf::CIE>(&Entry)) {
200
W.startLine() << format("[0x%" PRIx64 "] CIE length=%" PRIu64 "\n",
201
Address + CIE->getOffset(), CIE->getLength());
202
W.indent();
203
204
W.printNumber("version", CIE->getVersion());
205
W.printString("augmentation", CIE->getAugmentationString());
206
W.printNumber("code_alignment_factor", CIE->getCodeAlignmentFactor());
207
W.printNumber("data_alignment_factor", CIE->getDataAlignmentFactor());
208
W.printNumber("return_address_register", CIE->getReturnAddressRegister());
209
} else {
210
const dwarf::FDE *FDE = cast<dwarf::FDE>(&Entry);
211
W.startLine() << format("[0x%" PRIx64 "] FDE length=%" PRIu64
212
" cie=[0x%" PRIx64 "]\n",
213
Address + FDE->getOffset(), FDE->getLength(),
214
Address + FDE->getLinkedCIE()->getOffset());
215
W.indent();
216
217
InitialLocation = FDE->getInitialLocation();
218
W.startLine() << format("initial_location: 0x%" PRIx64 "\n",
219
*InitialLocation);
220
W.startLine() << format(
221
"address_range: 0x%" PRIx64 " (end : 0x%" PRIx64 ")\n",
222
FDE->getAddressRange(),
223
FDE->getInitialLocation() + FDE->getAddressRange());
224
}
225
226
W.getOStream() << "\n";
227
W.startLine() << "Program:\n";
228
W.indent();
229
auto DumpOpts = DIDumpOptions();
230
DumpOpts.IsEH = true;
231
Entry.cfis().dump(W.getOStream(), DumpOpts, W.getIndentLevel(),
232
InitialLocation);
233
W.unindent();
234
W.unindent();
235
W.getOStream() << "\n";
236
}
237
238
W.unindent();
239
}
240
} // namespace DwarfCFIEH
241
} // namespace llvm
242
243
#endif
244
245