LLVM 24.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"
29#include <cassert>
30#include <cinttypes>
31#include <cstdint>
32#include <optional>
33
34using namespace llvm;
35using namespace dwarf;
36
38 const CIE *Cie = Fde->getLinkedCIE();
39 if (Cie == nullptr)
41 "unable to get CIE for FDE at offset 0x%" PRIx64,
42 Fde->getOffset());
43
44 // Rows will be empty if there are no CFI instructions.
45 if (Cie->cfis().empty() && Fde->cfis().empty())
46 return UnwindTable({});
47
49 UnwindRow Row;
51 if (Error CieError = parseRows(Cie->cfis(), Row, nullptr).moveInto(CieRows))
52 return std::move(CieError);
53 // We need to save the initial locations of registers from the CIE parsing
54 // in case we run into DW_CFA_restore or DW_CFA_restore_extended opcodes.
56 const RegisterLocations InitialLocs = Row.getRegisterLocations();
57 if (Error FdeError =
58 parseRows(Fde->cfis(), Row, &InitialLocs).moveInto(FdeRows))
59 return std::move(FdeError);
60
62 AllRows.insert(AllRows.end(), CieRows.begin(), CieRows.end());
63 AllRows.insert(AllRows.end(), FdeRows.begin(), FdeRows.end());
64
65 // May be all the CFI instructions were DW_CFA_nop amd Row becomes empty.
66 // Do not add that to the unwind table.
67 if (Row.getRegisterLocations().hasLocations() ||
68 Row.getCFAValue().getLocation() != UnwindLocation::Unspecified)
69 AllRows.push_back(Row);
70 return UnwindTable(std::move(AllRows));
71}
72
74 // Rows will be empty if there are no CFI instructions.
75 if (Cie->cfis().empty())
76 return UnwindTable({});
77
79 UnwindRow Row;
80 if (Error CieError = parseRows(Cie->cfis(), Row, nullptr).moveInto(Rows))
81 return std::move(CieError);
82 // May be all the CFI instructions were DW_CFA_nop amd Row becomes empty.
83 // Do not add that to the unwind table.
84 if (Row.getRegisterLocations().hasLocations() ||
85 Row.getCFAValue().getLocation() != UnwindLocation::Unspecified)
86 Rows.push_back(Row);
87 return UnwindTable(std::move(Rows));
88}
89
90// Returns the CIE identifier to be used by the requested format.
91// CIE ids for .debug_frame sections are defined in Section 7.24 of DWARFv5.
92// For CIE ID in .eh_frame sections see
93// https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
94constexpr uint64_t getCIEId(bool IsDWARF64, bool IsEH) {
95 if (IsEH)
96 return 0;
97 if (IsDWARF64)
98 return DW64_CIE_ID;
99 return DW_CIE_ID;
100}
101
102void CIE::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
103 // A CIE with a zero length is a terminator entry in the .eh_frame section.
104 if (DumpOpts.IsEH && Length == 0) {
105 OS << formatv("{0:x-8}", Offset) << " ZERO terminator\n";
106 return;
107 }
108
109 OS << formatv("{0:x-8}", Offset)
110 << formatv(" {0:x-}",
112 << formatv(" {0:x-}",
114 IsDWARF64 && !DumpOpts.IsEH ? 16 : 8, '0'))
115 << " CIE\n"
116 << " Format: " << FormatString(IsDWARF64) << "\n";
117 if (DumpOpts.IsEH && Version != 1)
118 OS << "WARNING: unsupported CIE version\n";
119 OS << formatv(" Version: {0}\n", Version)
120 << " Augmentation: \"" << Augmentation << "\"\n";
121 if (Version >= 4) {
122 OS << formatv(" Address size: {0}\n", (uint32_t)AddressSize);
123 OS << formatv(" Segment desc size: {0}\n",
124 (uint32_t)SegmentDescriptorSize);
125 }
126 OS << formatv(" Code alignment factor: {0}\n",
127 (uint32_t)CodeAlignmentFactor);
128 OS << formatv(" Data alignment factor: {0}\n", (int32_t)DataAlignmentFactor);
129 OS << formatv(" Return address column: {0}\n",
130 (int32_t)ReturnAddressRegister);
131 if (Personality)
132 OS << formatv(" Personality Address: {0:x-16}\n", *Personality);
133 if (!AugmentationData.empty()) {
134 OS << " Augmentation data: ";
135 for (uint8_t Byte : AugmentationData)
136 OS << ' ' << hexdigit(Byte >> 4) << hexdigit(Byte & 0xf);
137 OS << "\n";
138 }
139 OS << "\n";
140 printCFIProgram(CFIs, OS, DumpOpts, /*IndentLevel=*/1,
141 /*InitialLocation=*/{});
142 OS << "\n";
143
144 if (Expected<UnwindTable> RowsOrErr = createUnwindTable(this))
145 printUnwindTable(*RowsOrErr, OS, DumpOpts, 1);
146 else {
149 "decoding the CIE opcodes into rows failed"),
150 RowsOrErr.takeError()));
151 }
152 OS << "\n";
153}
154
155void FDE::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
156 OS << formatv("{0:x-8}", Offset)
157 << formatv(" {0:x-}",
159 << formatv(" {0:x-}", fmt_align(CIEPointer, AlignStyle::Right,
160 IsDWARF64 && !DumpOpts.IsEH ? 16 : 8, '0'))
161 << " FDE cie=";
162 if (LinkedCIE)
163 OS << formatv("{0:x-8}", LinkedCIE->getOffset());
164 else
165 OS << "<invalid offset>";
166 OS << formatv(" pc={0:x-8}...{1:x-8}\n", InitialLocation,
167 InitialLocation + AddressRange);
168 OS << " Format: " << FormatString(IsDWARF64) << "\n";
169 if (LSDAAddress)
170 OS << formatv(" LSDA Address: {0:x-16}\n", *LSDAAddress);
171 printCFIProgram(CFIs, OS, DumpOpts, /*IndentLevel=*/1, InitialLocation);
172 OS << "\n";
173
174 if (Expected<UnwindTable> RowsOrErr = createUnwindTable(this))
175 printUnwindTable(*RowsOrErr, OS, DumpOpts, 1);
176 else {
179 "decoding the FDE opcodes into rows failed"),
180 RowsOrErr.takeError()));
181 }
182 OS << "\n";
183}
184
186 bool IsEH, uint64_t EHFrameAddress)
187 : Arch(Arch), IsEH(IsEH), EHFrameAddress(EHFrameAddress) {}
188
190
191[[maybe_unused]] static void dumpDataAux(DataExtractor Data, uint64_t Offset,
192 int Length) {
193 errs() << "DUMP: ";
194 for (int i = 0; i < Length; ++i) {
195 uint8_t c = Data.getU8(&Offset);
196 errs().write_hex(c); errs() << " ";
197 }
198 errs() << "\n";
199}
200
202 uint64_t Offset = 0;
204
205 // Retain the section contents so that the programs left undecoded below can
206 // be parsed on demand later.
207 if (!ParseCFIProgram)
208 this->Data = Data;
209
210 while (Data.isValidOffset(Offset)) {
211 uint64_t StartOffset = Offset;
212
213 uint64_t Length;
215 std::tie(Length, Format) = Data.getInitialLength(&Offset);
216 bool IsDWARF64 = Format == DWARF64;
217
218 // If the Length is 0, then this CIE is a terminator. We add it because some
219 // dumper tools might need it to print something special for such entries
220 // (e.g. llvm-objdump --dwarf=frames prints "ZERO terminator").
221 if (Length == 0) {
222 auto Cie = std::make_unique<CIE>(
223 IsDWARF64, StartOffset, 0, 0, SmallString<8>(), 0, 0, 0, 0, 0,
224 SmallString<8>(), 0, 0, std::nullopt, std::nullopt, Arch);
225 CIEs[StartOffset] = Cie.get();
226 Entries.push_back(std::move(Cie));
227 break;
228 }
229
230 // At this point, Offset points to the next field after Length.
231 // Length is the structure size excluding itself. Compute an offset one
232 // past the end of the structure (needed to know how many instructions to
233 // read).
234 uint64_t StartStructureOffset = Offset;
235 uint64_t EndStructureOffset = Offset + Length;
236
237 // The Id field's size depends on the DWARF format
238 Error Err = Error::success();
239 uint64_t Id = Data.getRelocatedValue((IsDWARF64 && !IsEH) ? 8 : 4, &Offset,
240 /*SectionIndex=*/nullptr, &Err);
241 if (Err)
242 return Err;
243
244 if (Id == getCIEId(IsDWARF64, IsEH)) {
245 uint8_t Version = Data.getU8(&Offset);
246 const char *Augmentation = Data.getCStr(&Offset);
247 StringRef AugmentationString(Augmentation ? Augmentation : "");
248 uint8_t AddressSize = Version < 4 ? Data.getAddressSize() :
249 Data.getU8(&Offset);
250 Data.setAddressSize(AddressSize);
251 uint8_t SegmentDescriptorSize = Version < 4 ? 0 : Data.getU8(&Offset);
252 uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset);
253 int64_t DataAlignmentFactor = Data.getSLEB128(&Offset);
254 uint64_t ReturnAddressRegister =
255 Version == 1 ? Data.getU8(&Offset) : Data.getULEB128(&Offset);
256
257 // Parse the augmentation data for EH CIEs
258 StringRef AugmentationData("");
259 uint32_t FDEPointerEncoding = DW_EH_PE_absptr;
260 uint32_t LSDAPointerEncoding = DW_EH_PE_omit;
261 std::optional<uint64_t> Personality;
262 std::optional<uint32_t> PersonalityEncoding;
263 if (IsEH) {
264 std::optional<uint64_t> AugmentationLength;
265 uint64_t StartAugmentationOffset;
266 uint64_t EndAugmentationOffset;
267
268 // Walk the augmentation string to get all the augmentation data.
269 for (unsigned i = 0, e = AugmentationString.size(); i != e; ++i) {
270 switch (AugmentationString[i]) {
271 default:
272 return createStringError(
274 "unknown augmentation character %c in entry at 0x%" PRIx64,
275 AugmentationString[i], StartOffset);
276 case 'L':
277 LSDAPointerEncoding = Data.getU8(&Offset);
278 break;
279 case 'P': {
280 if (Personality)
281 return createStringError(
283 "duplicate personality in entry at 0x%" PRIx64, StartOffset);
284 PersonalityEncoding = Data.getU8(&Offset);
285 Personality = Data.getEncodedPointer(
286 &Offset, *PersonalityEncoding,
287 EHFrameAddress ? EHFrameAddress + Offset : 0);
288 break;
289 }
290 case 'R':
291 FDEPointerEncoding = Data.getU8(&Offset);
292 break;
293 case 'S':
294 // Current frame is a signal trampoline.
295 break;
296 case 'z':
297 if (i)
298 return createStringError(
300 "'z' must be the first character at 0x%" PRIx64, StartOffset);
301 // Parse the augmentation length first. We only parse it if
302 // the string contains a 'z'.
303 AugmentationLength = Data.getULEB128(&Offset);
304 StartAugmentationOffset = Offset;
305 EndAugmentationOffset = Offset + *AugmentationLength;
306 break;
307 case 'B':
308 // B-Key is used for signing functions associated with this
309 // augmentation string
310 break;
311 // This stack frame contains MTE tagged data, so needs to be
312 // untagged on unwind.
313 case 'G':
314 break;
315 }
316 }
317
318 if (AugmentationLength) {
319 if (Offset != EndAugmentationOffset)
321 "parsing augmentation data at 0x%" PRIx64
322 " failed",
323 StartOffset);
324 AugmentationData = Data.getData().slice(StartAugmentationOffset,
325 EndAugmentationOffset);
326 }
327 }
328
329 auto Cie = std::make_unique<CIE>(
330 IsDWARF64, StartOffset, Length, Version, AugmentationString,
331 AddressSize, SegmentDescriptorSize, CodeAlignmentFactor,
332 DataAlignmentFactor, ReturnAddressRegister, AugmentationData,
333 FDEPointerEncoding, LSDAPointerEncoding, Personality,
334 PersonalityEncoding, Arch);
335 CIEs[StartOffset] = Cie.get();
336 Entries.emplace_back(std::move(Cie));
337 } else {
338 // FDE
339 uint64_t CIEPointer = Id;
340 uint64_t InitialLocation = 0;
341 uint64_t AddressRange = 0;
342 std::optional<uint64_t> LSDAAddress;
343 CIE *Cie = CIEs[IsEH ? (StartStructureOffset - CIEPointer) : CIEPointer];
344
345 if (IsEH) {
346 // The address size is encoded in the CIE we reference.
347 if (!Cie)
349 "parsing FDE data at 0x%" PRIx64
350 " failed due to missing CIE",
351 StartOffset);
352 if (auto Val =
353 Data.getEncodedPointer(&Offset, Cie->getFDEPointerEncoding(),
354 EHFrameAddress + Offset)) {
355 InitialLocation = *Val;
356 }
357 if (auto Val = Data.getEncodedPointer(
358 &Offset, Cie->getFDEPointerEncoding(), 0)) {
359 AddressRange = *Val;
360 }
361
362 StringRef AugmentationString = Cie->getAugmentationString();
363 if (!AugmentationString.empty()) {
364 // Parse the augmentation length and data for this FDE.
365 uint64_t AugmentationLength = Data.getULEB128(&Offset);
366
367 uint64_t EndAugmentationOffset = Offset + AugmentationLength;
368
369 // Decode the LSDA if the CIE augmentation string said we should.
371 LSDAAddress = Data.getEncodedPointer(
373 EHFrameAddress ? Offset + EHFrameAddress : 0);
374 }
375
376 if (Offset != EndAugmentationOffset)
378 "parsing augmentation data at 0x%" PRIx64
379 " failed",
380 StartOffset);
381 }
382 } else {
383 InitialLocation = Data.getRelocatedAddress(&Offset);
384 AddressRange = Data.getRelocatedAddress(&Offset);
385 }
386
387 Entries.emplace_back(new FDE(IsDWARF64, StartOffset, Length, CIEPointer,
388 InitialLocation, AddressRange, Cie,
389 LSDAAddress, Arch));
390 }
391
392 if (!ParseCFIProgram) {
393 // Record where this entry's CFI instructions begin, so that the program
394 // left undecoded here can be parsed on demand later.
395 Entries.back()->markCFIProgramUnparsed(Offset);
396 Offset = EndStructureOffset;
397 continue;
398 }
399
400 if (Error E =
401 Entries.back()->cfis().parse(Data, &Offset, EndStructureOffset))
402 return E;
403
404 if (Offset != EndStructureOffset)
405 return createStringError(
407 "parsing entry instructions at 0x%" PRIx64 " failed", StartOffset);
408 }
409
410 return Error::success();
411}
412
413FrameEntry *DWARFDebugFrame::getEntryAtOffset(uint64_t Offset) const {
414 auto It = partition_point(Entries, [=](const std::unique_ptr<FrameEntry> &E) {
415 return E->getOffset() < Offset;
416 });
417 if (It != Entries.end() && (*It)->getOffset() == Offset)
418 return It->get();
419 return nullptr;
420}
421
423 std::optional<uint64_t> StartOffset = Entry.getUnparsedCFIStartOffset();
424 if (!StartOffset)
425 return Error::success();
426
427 if (!Data)
428 return createStringError(
430 "cannot parse the instructions of the entry at 0x%" PRIx64
431 " on demand: the section contents were not retained",
432 Entry.getOffset());
433
434 uint64_t Offset = *StartOffset;
435 uint64_t EndOffset = Entry.getEndOffset();
436 assert(Offset >= Entry.getOffset() && Offset <= EndOffset &&
437 "entry does not know where its instructions begin");
438 DWARFDataExtractor EntryData = *Data;
439 // Clear previous unsuccessful parsing attempts, if any.
440 Entry.cfis().clear();
441 if (Error E = Entry.cfis().parse(EntryData, &Offset, EndOffset))
442 return E;
443
444 if (Offset != EndOffset)
446 "parsing entry instructions at 0x%" PRIx64
447 " failed",
448 Entry.getOffset());
449
450 // Signal we have a valid fully parsed CFI program.
451 Entry.markCFIProgramParsed();
452 return Error::success();
453}
454
456 for (const auto &Entry : Entries)
457 if (Error E = parseCFIProgram(*Entry))
458 return E;
459 return Error::success();
460}
461
462void DWARFDebugFrame::dumpEntry(FrameEntry &Entry, raw_ostream &OS,
463 DIDumpOptions DumpOpts) const {
464 if (const auto *Fde = dyn_cast<FDE>(&Entry))
465 if (const CIE *Cie = Fde->getLinkedCIE())
466 if (FrameEntry *CieEntry = getEntryAtOffset(Cie->getOffset()))
467 if (Error E = parseCFIProgram(*CieEntry))
468 DumpOpts.RecoverableErrorHandler(std::move(E));
469
470 if (Error E = parseCFIProgram(Entry))
471 DumpOpts.RecoverableErrorHandler(std::move(E));
472
473 Entry.dump(OS, DumpOpts);
474}
475
477 std::optional<uint64_t> Offset) const {
478 DumpOpts.IsEH = IsEH;
479 if (Offset) {
480 if (auto *Entry = getEntryAtOffset(*Offset))
481 dumpEntry(*Entry, OS, DumpOpts);
482 return;
483 }
484
485 OS << "\n";
486 for (const auto &Entry : Entries)
487 dumpEntry(*Entry, OS, DumpOpts);
488}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned uint64_t
constexpr uint64_t getCIEId(bool IsDWARF64, bool IsEH)
static void dumpDataAux(DataExtractor Data, uint64_t Offset, int Length)
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, bool ParseCFIProgram=true)
Parse the section from raw data.
LLVM_ABI Error parseAllCFIPrograms() const
Decode all the CFI instruction programs that parse() was told to skip.
LLVM_ABI Error parseCFIProgram(dwarf::FrameEntry &Entry) const
Decode the CFI instruction program of Entry if parse() was told to skip it.
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
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
constexpr bool empty() const
Check if the string is empty.
Definition StringRef.h:141
StringRef slice(size_t Start, size_t End) const
Return a reference to the substring from [Start, End).
Definition StringRef.h:720
constexpr size_t size() const
Get the string size.
Definition StringRef.h:144
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:1062
Calculates the starting offsets for various sections within the .debug_names section.
Definition Dwarf.h:35
const uint32_t DW_CIE_ID
Special ID values that distinguish a CIE from a FDE in DWARF CFI.
Definition Dwarf.h:98
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:99
DwarfFormat
Constants that define the DWARF format as 32 or 64 bit.
Definition Dwarf.h:93
@ DWARF64
Definition Dwarf.h:93
LLVM_ABI Expected< UnwindTable > createUnwindTable(const CIE *Cie)
Create an UnwindTable from a Common Information Entry (CIE).
@ DW_EH_PE_absptr
Definition Dwarf.h:951
@ DW_EH_PE_omit
Definition Dwarf.h:952
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:577
@ Length
Definition DWP.cpp:577
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
auto partition_point(R &&Range, Predicate P)
Binary search for the first iterator in a range where a predicate is false.
Definition STLExtras.h:2129
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition Error.h:1321
@ invalid_argument
Definition Errc.h:56
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
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).
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
support::detail::AlignAdapter< T > fmt_align(T &&Item, AlignStyle Where, size_t Amount, char Fill=' ')
Container for dump options that control which debug information will be dumped.
Definition DIContext.h:196
std::function< void(Error)> RecoverableErrorHandler
Definition DIContext.h:237