LLVM 23.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"
30#include <cassert>
31#include <cinttypes>
32#include <cstdint>
33#include <optional>
34
35using namespace llvm;
36using namespace dwarf;
37
39 const CIE *Cie = Fde->getLinkedCIE();
40 if (Cie == nullptr)
42 "unable to get CIE for FDE at offset 0x%" PRIx64,
43 Fde->getOffset());
44
45 // Rows will be empty if there are no CFI instructions.
46 if (Cie->cfis().empty() && Fde->cfis().empty())
47 return UnwindTable({});
48
50 UnwindRow Row;
52 if (Error CieError = parseRows(Cie->cfis(), Row, nullptr).moveInto(CieRows))
53 return std::move(CieError);
54 // We need to save the initial locations of registers from the CIE parsing
55 // in case we run into DW_CFA_restore or DW_CFA_restore_extended opcodes.
57 const RegisterLocations InitialLocs = Row.getRegisterLocations();
58 if (Error FdeError =
59 parseRows(Fde->cfis(), Row, &InitialLocs).moveInto(FdeRows))
60 return std::move(FdeError);
61
63 AllRows.insert(AllRows.end(), CieRows.begin(), CieRows.end());
64 AllRows.insert(AllRows.end(), FdeRows.begin(), FdeRows.end());
65
66 // May be all the CFI instructions were DW_CFA_nop amd Row becomes empty.
67 // Do not add that to the unwind table.
68 if (Row.getRegisterLocations().hasLocations() ||
69 Row.getCFAValue().getLocation() != UnwindLocation::Unspecified)
70 AllRows.push_back(Row);
71 return UnwindTable(std::move(AllRows));
72}
73
75 // Rows will be empty if there are no CFI instructions.
76 if (Cie->cfis().empty())
77 return UnwindTable({});
78
80 UnwindRow Row;
81 if (Error CieError = parseRows(Cie->cfis(), Row, nullptr).moveInto(Rows))
82 return std::move(CieError);
83 // May be all the CFI instructions were DW_CFA_nop amd Row becomes empty.
84 // Do not add that to the unwind table.
85 if (Row.getRegisterLocations().hasLocations() ||
86 Row.getCFAValue().getLocation() != UnwindLocation::Unspecified)
87 Rows.push_back(Row);
88 return UnwindTable(std::move(Rows));
89}
90
91// Returns the CIE identifier to be used by the requested format.
92// CIE ids for .debug_frame sections are defined in Section 7.24 of DWARFv5.
93// For CIE ID in .eh_frame sections see
94// https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
95constexpr uint64_t getCIEId(bool IsDWARF64, bool IsEH) {
96 if (IsEH)
97 return 0;
98 if (IsDWARF64)
99 return DW64_CIE_ID;
100 return DW_CIE_ID;
101}
102
103void CIE::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
104 // A CIE with a zero length is a terminator entry in the .eh_frame section.
105 if (DumpOpts.IsEH && Length == 0) {
106 OS << formatv("{0:x-8}", Offset) << " ZERO terminator\n";
107 return;
108 }
109
110 OS << formatv("{0:x-8}", Offset)
111 << formatv(" {0:x-}",
113 << formatv(" {0:x-}",
115 IsDWARF64 && !DumpOpts.IsEH ? 16 : 8, '0'))
116 << " CIE\n"
117 << " Format: " << FormatString(IsDWARF64) << "\n";
118 if (DumpOpts.IsEH && Version != 1)
119 OS << "WARNING: unsupported CIE version\n";
120 OS << formatv(" Version: {0}\n", Version)
121 << " Augmentation: \"" << Augmentation << "\"\n";
122 if (Version >= 4) {
123 OS << formatv(" Address size: {0}\n", (uint32_t)AddressSize);
124 OS << formatv(" Segment desc size: {0}\n",
125 (uint32_t)SegmentDescriptorSize);
126 }
127 OS << formatv(" Code alignment factor: {0}\n",
128 (uint32_t)CodeAlignmentFactor);
129 OS << formatv(" Data alignment factor: {0}\n", (int32_t)DataAlignmentFactor);
130 OS << formatv(" Return address column: {0}\n",
131 (int32_t)ReturnAddressRegister);
132 if (Personality)
133 OS << formatv(" Personality Address: {0:x-16}\n", *Personality);
134 if (!AugmentationData.empty()) {
135 OS << " Augmentation data: ";
136 for (uint8_t Byte : AugmentationData)
137 OS << ' ' << hexdigit(Byte >> 4) << hexdigit(Byte & 0xf);
138 OS << "\n";
139 }
140 OS << "\n";
141 printCFIProgram(CFIs, OS, DumpOpts, /*IndentLevel=*/1,
142 /*InitialLocation=*/{});
143 OS << "\n";
144
145 if (Expected<UnwindTable> RowsOrErr = createUnwindTable(this))
146 printUnwindTable(*RowsOrErr, OS, DumpOpts, 1);
147 else {
150 "decoding the CIE opcodes into rows failed"),
151 RowsOrErr.takeError()));
152 }
153 OS << "\n";
154}
155
156void FDE::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
157 OS << formatv("{0:x-8}", Offset)
158 << formatv(" {0:x-}",
160 << formatv(" {0:x-}", fmt_align(CIEPointer, AlignStyle::Right,
161 IsDWARF64 && !DumpOpts.IsEH ? 16 : 8, '0'))
162 << " FDE cie=";
163 if (LinkedCIE)
164 OS << formatv("{0:x-8}", LinkedCIE->getOffset());
165 else
166 OS << "<invalid offset>";
167 OS << formatv(" pc={0:x-8}...{1:x-8}\n", InitialLocation,
168 InitialLocation + AddressRange);
169 OS << " Format: " << FormatString(IsDWARF64) << "\n";
170 if (LSDAAddress)
171 OS << formatv(" LSDA Address: {0:x-16}\n", *LSDAAddress);
172 printCFIProgram(CFIs, OS, DumpOpts, /*IndentLevel=*/1, InitialLocation);
173 OS << "\n";
174
175 if (Expected<UnwindTable> RowsOrErr = createUnwindTable(this))
176 printUnwindTable(*RowsOrErr, OS, DumpOpts, 1);
177 else {
180 "decoding the FDE opcodes into rows failed"),
181 RowsOrErr.takeError()));
182 }
183 OS << "\n";
184}
185
187 bool IsEH, uint64_t EHFrameAddress)
188 : Arch(Arch), IsEH(IsEH), EHFrameAddress(EHFrameAddress) {}
189
191
192[[maybe_unused]] static void dumpDataAux(DataExtractor Data, uint64_t Offset,
193 int Length) {
194 errs() << "DUMP: ";
195 for (int i = 0; i < Length; ++i) {
196 uint8_t c = Data.getU8(&Offset);
197 errs().write_hex(c); errs() << " ";
198 }
199 errs() << "\n";
200}
201
203 uint64_t Offset = 0;
205
206 while (Data.isValidOffset(Offset)) {
207 uint64_t StartOffset = Offset;
208
211 std::tie(Length, Format) = Data.getInitialLength(&Offset);
212 bool IsDWARF64 = Format == DWARF64;
213
214 // If the Length is 0, then this CIE is a terminator. We add it because some
215 // dumper tools might need it to print something special for such entries
216 // (e.g. llvm-objdump --dwarf=frames prints "ZERO terminator").
217 if (Length == 0) {
218 auto Cie = std::make_unique<CIE>(
219 IsDWARF64, StartOffset, 0, 0, SmallString<8>(), 0, 0, 0, 0, 0,
220 SmallString<8>(), 0, 0, std::nullopt, std::nullopt, Arch);
221 CIEs[StartOffset] = Cie.get();
222 Entries.push_back(std::move(Cie));
223 break;
224 }
225
226 // At this point, Offset points to the next field after Length.
227 // Length is the structure size excluding itself. Compute an offset one
228 // past the end of the structure (needed to know how many instructions to
229 // read).
230 uint64_t StartStructureOffset = Offset;
231 uint64_t EndStructureOffset = Offset + Length;
232
233 // The Id field's size depends on the DWARF format
234 Error Err = Error::success();
235 uint64_t Id = Data.getRelocatedValue((IsDWARF64 && !IsEH) ? 8 : 4, &Offset,
236 /*SectionIndex=*/nullptr, &Err);
237 if (Err)
238 return Err;
239
240 if (Id == getCIEId(IsDWARF64, IsEH)) {
241 uint8_t Version = Data.getU8(&Offset);
242 const char *Augmentation = Data.getCStr(&Offset);
243 StringRef AugmentationString(Augmentation ? Augmentation : "");
244 uint8_t AddressSize = Version < 4 ? Data.getAddressSize() :
245 Data.getU8(&Offset);
246 Data.setAddressSize(AddressSize);
247 uint8_t SegmentDescriptorSize = Version < 4 ? 0 : Data.getU8(&Offset);
248 uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset);
249 int64_t DataAlignmentFactor = Data.getSLEB128(&Offset);
250 uint64_t ReturnAddressRegister =
251 Version == 1 ? Data.getU8(&Offset) : Data.getULEB128(&Offset);
252
253 // Parse the augmentation data for EH CIEs
254 StringRef AugmentationData("");
255 uint32_t FDEPointerEncoding = DW_EH_PE_absptr;
256 uint32_t LSDAPointerEncoding = DW_EH_PE_omit;
257 std::optional<uint64_t> Personality;
258 std::optional<uint32_t> PersonalityEncoding;
259 if (IsEH) {
260 std::optional<uint64_t> AugmentationLength;
261 uint64_t StartAugmentationOffset;
262 uint64_t EndAugmentationOffset;
263
264 // Walk the augmentation string to get all the augmentation data.
265 for (unsigned i = 0, e = AugmentationString.size(); i != e; ++i) {
266 switch (AugmentationString[i]) {
267 default:
268 return createStringError(
270 "unknown augmentation character %c in entry at 0x%" PRIx64,
271 AugmentationString[i], StartOffset);
272 case 'L':
273 LSDAPointerEncoding = Data.getU8(&Offset);
274 break;
275 case 'P': {
276 if (Personality)
277 return createStringError(
279 "duplicate personality in entry at 0x%" PRIx64, StartOffset);
280 PersonalityEncoding = Data.getU8(&Offset);
281 Personality = Data.getEncodedPointer(
282 &Offset, *PersonalityEncoding,
283 EHFrameAddress ? EHFrameAddress + Offset : 0);
284 break;
285 }
286 case 'R':
287 FDEPointerEncoding = Data.getU8(&Offset);
288 break;
289 case 'S':
290 // Current frame is a signal trampoline.
291 break;
292 case 'z':
293 if (i)
294 return createStringError(
296 "'z' must be the first character at 0x%" PRIx64, StartOffset);
297 // Parse the augmentation length first. We only parse it if
298 // the string contains a 'z'.
299 AugmentationLength = Data.getULEB128(&Offset);
300 StartAugmentationOffset = Offset;
301 EndAugmentationOffset = Offset + *AugmentationLength;
302 break;
303 case 'B':
304 // B-Key is used for signing functions associated with this
305 // augmentation string
306 break;
307 // This stack frame contains MTE tagged data, so needs to be
308 // untagged on unwind.
309 case 'G':
310 break;
311 }
312 }
313
314 if (AugmentationLength) {
315 if (Offset != EndAugmentationOffset)
317 "parsing augmentation data at 0x%" PRIx64
318 " failed",
319 StartOffset);
320 AugmentationData = Data.getData().slice(StartAugmentationOffset,
321 EndAugmentationOffset);
322 }
323 }
324
325 auto Cie = std::make_unique<CIE>(
326 IsDWARF64, StartOffset, Length, Version, AugmentationString,
327 AddressSize, SegmentDescriptorSize, CodeAlignmentFactor,
328 DataAlignmentFactor, ReturnAddressRegister, AugmentationData,
329 FDEPointerEncoding, LSDAPointerEncoding, Personality,
330 PersonalityEncoding, Arch);
331 CIEs[StartOffset] = Cie.get();
332 Entries.emplace_back(std::move(Cie));
333 } else {
334 // FDE
335 uint64_t CIEPointer = Id;
336 uint64_t InitialLocation = 0;
338 std::optional<uint64_t> LSDAAddress;
339 CIE *Cie = CIEs[IsEH ? (StartStructureOffset - CIEPointer) : CIEPointer];
340
341 if (IsEH) {
342 // The address size is encoded in the CIE we reference.
343 if (!Cie)
345 "parsing FDE data at 0x%" PRIx64
346 " failed due to missing CIE",
347 StartOffset);
348 if (auto Val =
349 Data.getEncodedPointer(&Offset, Cie->getFDEPointerEncoding(),
350 EHFrameAddress + Offset)) {
351 InitialLocation = *Val;
352 }
353 if (auto Val = Data.getEncodedPointer(
354 &Offset, Cie->getFDEPointerEncoding(), 0)) {
355 AddressRange = *Val;
356 }
357
358 StringRef AugmentationString = Cie->getAugmentationString();
359 if (!AugmentationString.empty()) {
360 // Parse the augmentation length and data for this FDE.
361 uint64_t AugmentationLength = Data.getULEB128(&Offset);
362
363 uint64_t EndAugmentationOffset = Offset + AugmentationLength;
364
365 // Decode the LSDA if the CIE augmentation string said we should.
367 LSDAAddress = Data.getEncodedPointer(
369 EHFrameAddress ? Offset + EHFrameAddress : 0);
370 }
371
372 if (Offset != EndAugmentationOffset)
374 "parsing augmentation data at 0x%" PRIx64
375 " failed",
376 StartOffset);
377 }
378 } else {
379 InitialLocation = Data.getRelocatedAddress(&Offset);
380 AddressRange = Data.getRelocatedAddress(&Offset);
381 }
382
383 Entries.emplace_back(new FDE(IsDWARF64, StartOffset, Length, CIEPointer,
384 InitialLocation, AddressRange, Cie,
385 LSDAAddress, Arch));
386 }
387
388 if (Error E =
389 Entries.back()->cfis().parse(Data, &Offset, EndStructureOffset))
390 return E;
391
392 if (Offset != EndStructureOffset)
393 return createStringError(
395 "parsing entry instructions at 0x%" PRIx64 " failed", StartOffset);
396 }
397
398 return Error::success();
399}
400
401FrameEntry *DWARFDebugFrame::getEntryAtOffset(uint64_t Offset) const {
402 auto It = partition_point(Entries, [=](const std::unique_ptr<FrameEntry> &E) {
403 return E->getOffset() < Offset;
404 });
405 if (It != Entries.end() && (*It)->getOffset() == Offset)
406 return It->get();
407 return nullptr;
408}
409
411 std::optional<uint64_t> Offset) const {
412 DumpOpts.IsEH = IsEH;
413 if (Offset) {
414 if (auto *Entry = getEntryAtOffset(*Offset))
415 Entry->dump(OS, DumpOpts);
416 return;
417 }
418
419 OS << "\n";
420 for (const auto &Entry : Entries)
421 Entry->dump(OS, DumpOpts);
422}
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)
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:140
constexpr size_t size() const
size - Get the string size.
Definition StringRef.h:143
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:1023
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:868
@ DW_EH_PE_omit
Definition Dwarf.h:869
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:532
@ Length
Definition DWP.cpp:532
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)
FunctionAddr VTableAddr uintptr_t uintptr_t Version
Definition InstrProf.h:334
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.
FunctionAddr VTableAddr uintptr_t uintptr_t Data
Definition InstrProf.h:221
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