LLVM 22.0.0git
DWARFDebugFrame.cpp
Go to the documentation of this file.
1//===- DWARFDebugFrame.h - Parsing of .debug_frame ------------------------===//
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
10#include "llvm/ADT/DenseMap.h"
12#include "llvm/ADT/StringRef.h"
23#include "llvm/Support/Errc.h"
24#include "llvm/Support/Error.h"
26#include "llvm/Support/Format.h"
28#include <cassert>
29#include <cinttypes>
30#include <cstdint>
31#include <optional>
32
33using namespace llvm;
34using namespace dwarf;
35
37 const CIE *Cie = Fde->getLinkedCIE();
38 if (Cie == nullptr)
40 "unable to get CIE for FDE at offset 0x%" PRIx64,
41 Fde->getOffset());
42
43 // Rows will be empty if there are no CFI instructions.
44 if (Cie->cfis().empty() && Fde->cfis().empty())
45 return UnwindTable({});
46
48 UnwindRow Row;
50 if (Error CieError = parseRows(Cie->cfis(), Row, nullptr).moveInto(CieRows))
51 return std::move(CieError);
52 // We need to save the initial locations of registers from the CIE parsing
53 // in case we run into DW_CFA_restore or DW_CFA_restore_extended opcodes.
55 const RegisterLocations InitialLocs = Row.getRegisterLocations();
56 if (Error FdeError =
57 parseRows(Fde->cfis(), Row, &InitialLocs).moveInto(FdeRows))
58 return std::move(FdeError);
59
61 AllRows.insert(AllRows.end(), CieRows.begin(), CieRows.end());
62 AllRows.insert(AllRows.end(), FdeRows.begin(), FdeRows.end());
63
64 // May be all the CFI instructions were DW_CFA_nop amd Row becomes empty.
65 // Do not add that to the unwind table.
66 if (Row.getRegisterLocations().hasLocations() ||
67 Row.getCFAValue().getLocation() != UnwindLocation::Unspecified)
68 AllRows.push_back(Row);
69 return UnwindTable(std::move(AllRows));
70}
71
73 // Rows will be empty if there are no CFI instructions.
74 if (Cie->cfis().empty())
75 return UnwindTable({});
76
78 UnwindRow Row;
79 if (Error CieError = parseRows(Cie->cfis(), Row, nullptr).moveInto(Rows))
80 return std::move(CieError);
81 // May be all the CFI instructions were DW_CFA_nop amd Row becomes empty.
82 // Do not add that to the unwind table.
83 if (Row.getRegisterLocations().hasLocations() ||
84 Row.getCFAValue().getLocation() != UnwindLocation::Unspecified)
85 Rows.push_back(Row);
86 return UnwindTable(std::move(Rows));
87}
88
89// Returns the CIE identifier to be used by the requested format.
90// CIE ids for .debug_frame sections are defined in Section 7.24 of DWARFv5.
91// For CIE ID in .eh_frame sections see
92// https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
93constexpr uint64_t getCIEId(bool IsDWARF64, bool IsEH) {
94 if (IsEH)
95 return 0;
96 if (IsDWARF64)
97 return DW64_CIE_ID;
98 return DW_CIE_ID;
99}
100
101void CIE::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
102 // A CIE with a zero length is a terminator entry in the .eh_frame section.
103 if (DumpOpts.IsEH && Length == 0) {
104 OS << format("%08" PRIx64, Offset) << " ZERO terminator\n";
105 return;
106 }
107
108 OS << format("%08" PRIx64, Offset)
109 << format(" %0*" PRIx64, IsDWARF64 ? 16 : 8, Length)
110 << format(" %0*" PRIx64, IsDWARF64 && !DumpOpts.IsEH ? 16 : 8,
111 getCIEId(IsDWARF64, DumpOpts.IsEH))
112 << " CIE\n"
113 << " Format: " << FormatString(IsDWARF64) << "\n";
114 if (DumpOpts.IsEH && Version != 1)
115 OS << "WARNING: unsupported CIE version\n";
116 OS << format(" Version: %d\n", Version)
117 << " Augmentation: \"" << Augmentation << "\"\n";
118 if (Version >= 4) {
119 OS << format(" Address size: %u\n", (uint32_t)AddressSize);
120 OS << format(" Segment desc size: %u\n",
121 (uint32_t)SegmentDescriptorSize);
122 }
123 OS << format(" Code alignment factor: %u\n", (uint32_t)CodeAlignmentFactor);
124 OS << format(" Data alignment factor: %d\n", (int32_t)DataAlignmentFactor);
125 OS << format(" Return address column: %d\n", (int32_t)ReturnAddressRegister);
126 if (Personality)
127 OS << format(" Personality Address: %016" PRIx64 "\n", *Personality);
128 if (!AugmentationData.empty()) {
129 OS << " Augmentation data: ";
130 for (uint8_t Byte : AugmentationData)
131 OS << ' ' << hexdigit(Byte >> 4) << hexdigit(Byte & 0xf);
132 OS << "\n";
133 }
134 OS << "\n";
135 printCFIProgram(CFIs, OS, DumpOpts, /*IndentLevel=*/1,
136 /*InitialLocation=*/{});
137 OS << "\n";
138
139 if (Expected<UnwindTable> RowsOrErr = createUnwindTable(this))
140 printUnwindTable(*RowsOrErr, OS, DumpOpts, 1);
141 else {
144 "decoding the CIE opcodes into rows failed"),
145 RowsOrErr.takeError()));
146 }
147 OS << "\n";
148}
149
150void FDE::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
151 OS << format("%08" PRIx64, Offset)
152 << format(" %0*" PRIx64, IsDWARF64 ? 16 : 8, Length)
153 << format(" %0*" PRIx64, IsDWARF64 && !DumpOpts.IsEH ? 16 : 8, CIEPointer)
154 << " FDE cie=";
155 if (LinkedCIE)
156 OS << format("%08" PRIx64, LinkedCIE->getOffset());
157 else
158 OS << "<invalid offset>";
159 OS << format(" pc=%08" PRIx64 "...%08" PRIx64 "\n", InitialLocation,
160 InitialLocation + AddressRange);
161 OS << " Format: " << FormatString(IsDWARF64) << "\n";
162 if (LSDAAddress)
163 OS << format(" LSDA Address: %016" PRIx64 "\n", *LSDAAddress);
164 printCFIProgram(CFIs, OS, DumpOpts, /*IndentLevel=*/1, InitialLocation);
165 OS << "\n";
166
167 if (Expected<UnwindTable> RowsOrErr = createUnwindTable(this))
168 printUnwindTable(*RowsOrErr, OS, DumpOpts, 1);
169 else {
172 "decoding the FDE opcodes into rows failed"),
173 RowsOrErr.takeError()));
174 }
175 OS << "\n";
176}
177
179 bool IsEH, uint64_t EHFrameAddress)
180 : Arch(Arch), IsEH(IsEH), EHFrameAddress(EHFrameAddress) {}
181
183
185 uint64_t Offset, int Length) {
186 errs() << "DUMP: ";
187 for (int i = 0; i < Length; ++i) {
188 uint8_t c = Data.getU8(&Offset);
189 errs().write_hex(c); errs() << " ";
190 }
191 errs() << "\n";
192}
193
195 uint64_t Offset = 0;
197
198 while (Data.isValidOffset(Offset)) {
199 uint64_t StartOffset = Offset;
200
203 std::tie(Length, Format) = Data.getInitialLength(&Offset);
204 bool IsDWARF64 = Format == DWARF64;
205
206 // If the Length is 0, then this CIE is a terminator. We add it because some
207 // dumper tools might need it to print something special for such entries
208 // (e.g. llvm-objdump --dwarf=frames prints "ZERO terminator").
209 if (Length == 0) {
210 auto Cie = std::make_unique<CIE>(
211 IsDWARF64, StartOffset, 0, 0, SmallString<8>(), 0, 0, 0, 0, 0,
212 SmallString<8>(), 0, 0, std::nullopt, std::nullopt, Arch);
213 CIEs[StartOffset] = Cie.get();
214 Entries.push_back(std::move(Cie));
215 break;
216 }
217
218 // At this point, Offset points to the next field after Length.
219 // Length is the structure size excluding itself. Compute an offset one
220 // past the end of the structure (needed to know how many instructions to
221 // read).
222 uint64_t StartStructureOffset = Offset;
223 uint64_t EndStructureOffset = Offset + Length;
224
225 // The Id field's size depends on the DWARF format
226 Error Err = Error::success();
227 uint64_t Id = Data.getRelocatedValue((IsDWARF64 && !IsEH) ? 8 : 4, &Offset,
228 /*SectionIndex=*/nullptr, &Err);
229 if (Err)
230 return Err;
231
232 if (Id == getCIEId(IsDWARF64, IsEH)) {
233 uint8_t Version = Data.getU8(&Offset);
234 const char *Augmentation = Data.getCStr(&Offset);
235 StringRef AugmentationString(Augmentation ? Augmentation : "");
236 uint8_t AddressSize = Version < 4 ? Data.getAddressSize() :
237 Data.getU8(&Offset);
238 Data.setAddressSize(AddressSize);
239 uint8_t SegmentDescriptorSize = Version < 4 ? 0 : Data.getU8(&Offset);
240 uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset);
241 int64_t DataAlignmentFactor = Data.getSLEB128(&Offset);
242 uint64_t ReturnAddressRegister =
243 Version == 1 ? Data.getU8(&Offset) : Data.getULEB128(&Offset);
244
245 // Parse the augmentation data for EH CIEs
246 StringRef AugmentationData("");
247 uint32_t FDEPointerEncoding = DW_EH_PE_absptr;
248 uint32_t LSDAPointerEncoding = DW_EH_PE_omit;
249 std::optional<uint64_t> Personality;
250 std::optional<uint32_t> PersonalityEncoding;
251 if (IsEH) {
252 std::optional<uint64_t> AugmentationLength;
253 uint64_t StartAugmentationOffset;
254 uint64_t EndAugmentationOffset;
255
256 // Walk the augmentation string to get all the augmentation data.
257 for (unsigned i = 0, e = AugmentationString.size(); i != e; ++i) {
258 switch (AugmentationString[i]) {
259 default:
260 return createStringError(
262 "unknown augmentation character %c in entry at 0x%" PRIx64,
263 AugmentationString[i], StartOffset);
264 case 'L':
265 LSDAPointerEncoding = Data.getU8(&Offset);
266 break;
267 case 'P': {
268 if (Personality)
269 return createStringError(
271 "duplicate personality in entry at 0x%" PRIx64, StartOffset);
272 PersonalityEncoding = Data.getU8(&Offset);
273 Personality = Data.getEncodedPointer(
274 &Offset, *PersonalityEncoding,
275 EHFrameAddress ? EHFrameAddress + Offset : 0);
276 break;
277 }
278 case 'R':
279 FDEPointerEncoding = Data.getU8(&Offset);
280 break;
281 case 'S':
282 // Current frame is a signal trampoline.
283 break;
284 case 'z':
285 if (i)
286 return createStringError(
288 "'z' must be the first character at 0x%" PRIx64, StartOffset);
289 // Parse the augmentation length first. We only parse it if
290 // the string contains a 'z'.
291 AugmentationLength = Data.getULEB128(&Offset);
292 StartAugmentationOffset = Offset;
293 EndAugmentationOffset = Offset + *AugmentationLength;
294 break;
295 case 'B':
296 // B-Key is used for signing functions associated with this
297 // augmentation string
298 break;
299 // This stack frame contains MTE tagged data, so needs to be
300 // untagged on unwind.
301 case 'G':
302 break;
303 }
304 }
305
306 if (AugmentationLength) {
307 if (Offset != EndAugmentationOffset)
309 "parsing augmentation data at 0x%" PRIx64
310 " failed",
311 StartOffset);
312 AugmentationData = Data.getData().slice(StartAugmentationOffset,
313 EndAugmentationOffset);
314 }
315 }
316
317 auto Cie = std::make_unique<CIE>(
318 IsDWARF64, StartOffset, Length, Version, AugmentationString,
319 AddressSize, SegmentDescriptorSize, CodeAlignmentFactor,
320 DataAlignmentFactor, ReturnAddressRegister, AugmentationData,
321 FDEPointerEncoding, LSDAPointerEncoding, Personality,
322 PersonalityEncoding, Arch);
323 CIEs[StartOffset] = Cie.get();
324 Entries.emplace_back(std::move(Cie));
325 } else {
326 // FDE
327 uint64_t CIEPointer = Id;
328 uint64_t InitialLocation = 0;
330 std::optional<uint64_t> LSDAAddress;
331 CIE *Cie = CIEs[IsEH ? (StartStructureOffset - CIEPointer) : CIEPointer];
332
333 if (IsEH) {
334 // The address size is encoded in the CIE we reference.
335 if (!Cie)
337 "parsing FDE data at 0x%" PRIx64
338 " failed due to missing CIE",
339 StartOffset);
340 if (auto Val =
341 Data.getEncodedPointer(&Offset, Cie->getFDEPointerEncoding(),
342 EHFrameAddress + Offset)) {
343 InitialLocation = *Val;
344 }
345 if (auto Val = Data.getEncodedPointer(
346 &Offset, Cie->getFDEPointerEncoding(), 0)) {
347 AddressRange = *Val;
348 }
349
350 StringRef AugmentationString = Cie->getAugmentationString();
351 if (!AugmentationString.empty()) {
352 // Parse the augmentation length and data for this FDE.
353 uint64_t AugmentationLength = Data.getULEB128(&Offset);
354
355 uint64_t EndAugmentationOffset = Offset + AugmentationLength;
356
357 // Decode the LSDA if the CIE augmentation string said we should.
359 LSDAAddress = Data.getEncodedPointer(
361 EHFrameAddress ? Offset + EHFrameAddress : 0);
362 }
363
364 if (Offset != EndAugmentationOffset)
366 "parsing augmentation data at 0x%" PRIx64
367 " failed",
368 StartOffset);
369 }
370 } else {
371 InitialLocation = Data.getRelocatedAddress(&Offset);
372 AddressRange = Data.getRelocatedAddress(&Offset);
373 }
374
375 Entries.emplace_back(new FDE(IsDWARF64, StartOffset, Length, CIEPointer,
376 InitialLocation, AddressRange, Cie,
377 LSDAAddress, Arch));
378 }
379
380 if (Error E =
381 Entries.back()->cfis().parse(Data, &Offset, EndStructureOffset))
382 return E;
383
384 if (Offset != EndStructureOffset)
385 return createStringError(
387 "parsing entry instructions at 0x%" PRIx64 " failed", StartOffset);
388 }
389
390 return Error::success();
391}
392
393FrameEntry *DWARFDebugFrame::getEntryAtOffset(uint64_t Offset) const {
394 auto It = partition_point(Entries, [=](const std::unique_ptr<FrameEntry> &E) {
395 return E->getOffset() < Offset;
396 });
397 if (It != Entries.end() && (*It)->getOffset() == Offset)
398 return It->get();
399 return nullptr;
400}
401
403 std::optional<uint64_t> Offset) const {
404 DumpOpts.IsEH = IsEH;
405 if (Offset) {
406 if (auto *Entry = getEntryAtOffset(*Offset))
407 Entry->dump(OS, DumpOpts);
408 return;
409 }
410
411 OS << "\n";
412 for (const auto &Entry : Entries)
413 Entry->dump(OS, DumpOpts);
414}
#define LLVM_ATTRIBUTE_UNUSED
Definition Compiler.h:298
static void LLVM_ATTRIBUTE_UNUSED dumpDataAux(DataExtractor Data, uint64_t Offset, int Length)
constexpr uint64_t getCIEId(bool IsDWARF64, bool IsEH)
This file defines the DenseMap class.
This file contains constants used for implementing Dwarf debug support.
This file contains some functions that are useful when dealing with strings.
A class that represents an address range.
A DWARFDataExtractor (typically for an in-memory copy of an object-file section) plus a relocation ma...
LLVM_ABI DWARFDebugFrame(Triple::ArchType Arch, bool IsEH=false, uint64_t EHFrameAddress=0)
LLVM_ABI void dump(raw_ostream &OS, DIDumpOptions DumpOpts, std::optional< uint64_t > Offset) const
Dump the section data into the given stream.
LLVM_ABI ~DWARFDebugFrame()
LLVM_ABI Error parse(DWARFDataExtractor Data)
Parse the section from raw data.
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition SmallString.h:26
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
constexpr bool empty() const
empty - Check if the string is empty.
Definition StringRef.h:151
constexpr size_t size() const
size - Get the string size.
Definition StringRef.h:154
DWARF Common Information Entry (CIE)
void dump(raw_ostream &OS, DIDumpOptions DumpOpts) const override
Dump the instructions in this CFI fragment.
uint32_t getLSDAPointerEncoding() const
uint32_t getFDEPointerEncoding() const
StringRef getAugmentationString() const
DWARF Frame Description Entry (FDE)
uint64_t getInitialLocation() const
const CIE * getLinkedCIE() const
void dump(raw_ostream &OS, DIDumpOptions DumpOpts) const override
Dump the instructions in this CFI fragment.
An entry in either debug_frame or eh_frame.
const uint64_t Length
Entry length as specified in DWARF.
const uint64_t Offset
Offset of this entry in the section.
const CFIProgram & cfis() const
uint64_t getOffset() const
A class that can track all registers with locations in a UnwindRow object.
A class that represents a single row in the unwind table that is decoded by parsing the DWARF Call Fr...
void setAddress(uint64_t Addr)
Set the address for this UnwindRow.
A class that contains all UnwindRow objects for an FDE or a single unwind row for a CIE.
std::vector< UnwindRow > RowContainer
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
raw_ostream & write_hex(unsigned long long N)
Output N in hexadecimal, without any prefix or padding.
LLVM_ABI StringRef FormatString(DwarfFormat Format)
Definition Dwarf.cpp:889
Calculates the starting offsets for various sections within the .debug_names section.
Definition Dwarf.h:34
const uint32_t DW_CIE_ID
Special ID values that distinguish a CIE from a FDE in DWARF CFI.
Definition Dwarf.h:97
LLVM_ABI void printUnwindTable(const UnwindTable &Rows, raw_ostream &OS, DIDumpOptions DumpOpts, unsigned IndentLevel=0)
Print a UnwindTable to the stream.
const uint64_t DW64_CIE_ID
Definition Dwarf.h:98
DwarfFormat
Constants that define the DWARF format as 32 or 64 bit.
Definition Dwarf.h:92
@ DWARF64
Definition Dwarf.h:92
LLVM_ABI Expected< UnwindTable > createUnwindTable(const CIE *Cie)
Create an UnwindTable from a Common Information Entry (CIE).
@ DW_EH_PE_absptr
Definition Dwarf.h:854
@ DW_EH_PE_omit
Definition Dwarf.h:855
LLVM_ABI Expected< UnwindTable::RowContainer > parseRows(const CFIProgram &CFIP, UnwindRow &CurrRow, const RegisterLocations *InitialLocs)
Parse the information in the CFIProgram and update the CurrRow object that the state machine describe...
LLVM_ABI void printCFIProgram(const CFIProgram &P, raw_ostream &OS, const DIDumpOptions &DumpOpts, unsigned IndentLevel, std::optional< uint64_t > Address)
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:477
@ Length
Definition DWP.cpp:477
auto partition_point(R &&Range, Predicate P)
Binary search for the first iterator in a range where a predicate is false.
Definition STLExtras.h:2053
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition Error.h:1305
@ invalid_argument
Definition Errc.h:56
FunctionAddr VTableAddr uintptr_t uintptr_t Version
Definition InstrProf.h:302
Error joinErrors(Error E1, Error E2)
Concatenate errors.
Definition Error.h:442
char hexdigit(unsigned X, bool LowerCase=false)
hexdigit - Return the hexadecimal character for the given number X (which should be less than 16).
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition Format.h:126
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
FunctionAddr VTableAddr uintptr_t uintptr_t Data
Definition InstrProf.h:189
Container for dump options that control which debug information will be dumped.
Definition DIContext.h:196
std::function< void(Error)> RecoverableErrorHandler
Definition DIContext.h:235