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 while (Data.isValidOffset(Offset)) {
206 uint64_t StartOffset = Offset;
207
208 uint64_t Length;
210 std::tie(Length, Format) = Data.getInitialLength(&Offset);
211 bool IsDWARF64 = Format == DWARF64;
212
213 // If the Length is 0, then this CIE is a terminator. We add it because some
214 // dumper tools might need it to print something special for such entries
215 // (e.g. llvm-objdump --dwarf=frames prints "ZERO terminator").
216 if (Length == 0) {
217 auto Cie = std::make_unique<CIE>(
218 IsDWARF64, StartOffset, 0, 0, SmallString<8>(), 0, 0, 0, 0, 0,
219 SmallString<8>(), 0, 0, std::nullopt, std::nullopt, Arch);
220 CIEs[StartOffset] = Cie.get();
221 Entries.push_back(std::move(Cie));
222 break;
223 }
224
225 // At this point, Offset points to the next field after Length.
226 // Length is the structure size excluding itself. Compute an offset one
227 // past the end of the structure (needed to know how many instructions to
228 // read).
229 uint64_t StartStructureOffset = Offset;
230 uint64_t EndStructureOffset = Offset + Length;
231
232 // The Id field's size depends on the DWARF format
233 Error Err = Error::success();
234 uint64_t Id = Data.getRelocatedValue((IsDWARF64 && !IsEH) ? 8 : 4, &Offset,
235 /*SectionIndex=*/nullptr, &Err);
236 if (Err)
237 return Err;
238
239 if (Id == getCIEId(IsDWARF64, IsEH)) {
240 uint8_t Version = Data.getU8(&Offset);
241 const char *Augmentation = Data.getCStr(&Offset);
242 StringRef AugmentationString(Augmentation ? Augmentation : "");
243 uint8_t AddressSize = Version < 4 ? Data.getAddressSize() :
244 Data.getU8(&Offset);
245 Data.setAddressSize(AddressSize);
246 uint8_t SegmentDescriptorSize = Version < 4 ? 0 : Data.getU8(&Offset);
247 uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset);
248 int64_t DataAlignmentFactor = Data.getSLEB128(&Offset);
249 uint64_t ReturnAddressRegister =
250 Version == 1 ? Data.getU8(&Offset) : Data.getULEB128(&Offset);
251
252 // Parse the augmentation data for EH CIEs
253 StringRef AugmentationData("");
254 uint32_t FDEPointerEncoding = DW_EH_PE_absptr;
255 uint32_t LSDAPointerEncoding = DW_EH_PE_omit;
256 std::optional<uint64_t> Personality;
257 std::optional<uint32_t> PersonalityEncoding;
258 if (IsEH) {
259 std::optional<uint64_t> AugmentationLength;
260 uint64_t StartAugmentationOffset;
261 uint64_t EndAugmentationOffset;
262
263 // Walk the augmentation string to get all the augmentation data.
264 for (unsigned i = 0, e = AugmentationString.size(); i != e; ++i) {
265 switch (AugmentationString[i]) {
266 default:
267 return createStringError(
269 "unknown augmentation character %c in entry at 0x%" PRIx64,
270 AugmentationString[i], StartOffset);
271 case 'L':
272 LSDAPointerEncoding = Data.getU8(&Offset);
273 break;
274 case 'P': {
275 if (Personality)
276 return createStringError(
278 "duplicate personality in entry at 0x%" PRIx64, StartOffset);
279 PersonalityEncoding = Data.getU8(&Offset);
280 Personality = Data.getEncodedPointer(
281 &Offset, *PersonalityEncoding,
282 EHFrameAddress ? EHFrameAddress + Offset : 0);
283 break;
284 }
285 case 'R':
286 FDEPointerEncoding = Data.getU8(&Offset);
287 break;
288 case 'S':
289 // Current frame is a signal trampoline.
290 break;
291 case 'z':
292 if (i)
293 return createStringError(
295 "'z' must be the first character at 0x%" PRIx64, StartOffset);
296 // Parse the augmentation length first. We only parse it if
297 // the string contains a 'z'.
298 AugmentationLength = Data.getULEB128(&Offset);
299 StartAugmentationOffset = Offset;
300 EndAugmentationOffset = Offset + *AugmentationLength;
301 break;
302 case 'B':
303 // B-Key is used for signing functions associated with this
304 // augmentation string
305 break;
306 // This stack frame contains MTE tagged data, so needs to be
307 // untagged on unwind.
308 case 'G':
309 break;
310 }
311 }
312
313 if (AugmentationLength) {
314 if (Offset != EndAugmentationOffset)
316 "parsing augmentation data at 0x%" PRIx64
317 " failed",
318 StartOffset);
319 AugmentationData = Data.getData().slice(StartAugmentationOffset,
320 EndAugmentationOffset);
321 }
322 }
323
324 auto Cie = std::make_unique<CIE>(
325 IsDWARF64, StartOffset, Length, Version, AugmentationString,
326 AddressSize, SegmentDescriptorSize, CodeAlignmentFactor,
327 DataAlignmentFactor, ReturnAddressRegister, AugmentationData,
328 FDEPointerEncoding, LSDAPointerEncoding, Personality,
329 PersonalityEncoding, Arch);
330 CIEs[StartOffset] = Cie.get();
331 Entries.emplace_back(std::move(Cie));
332 } else {
333 // FDE
334 uint64_t CIEPointer = Id;
335 uint64_t InitialLocation = 0;
336 uint64_t AddressRange = 0;
337 std::optional<uint64_t> LSDAAddress;
338 CIE *Cie = CIEs[IsEH ? (StartStructureOffset - CIEPointer) : CIEPointer];
339
340 if (IsEH) {
341 // The address size is encoded in the CIE we reference.
342 if (!Cie)
344 "parsing FDE data at 0x%" PRIx64
345 " failed due to missing CIE",
346 StartOffset);
347 if (auto Val =
348 Data.getEncodedPointer(&Offset, Cie->getFDEPointerEncoding(),
349 EHFrameAddress + Offset)) {
350 InitialLocation = *Val;
351 }
352 if (auto Val = Data.getEncodedPointer(
353 &Offset, Cie->getFDEPointerEncoding(), 0)) {
354 AddressRange = *Val;
355 }
356
357 StringRef AugmentationString = Cie->getAugmentationString();
358 if (!AugmentationString.empty()) {
359 // Parse the augmentation length and data for this FDE.
360 uint64_t AugmentationLength = Data.getULEB128(&Offset);
361
362 uint64_t EndAugmentationOffset = Offset + AugmentationLength;
363
364 // Decode the LSDA if the CIE augmentation string said we should.
366 LSDAAddress = Data.getEncodedPointer(
368 EHFrameAddress ? Offset + EHFrameAddress : 0);
369 }
370
371 if (Offset != EndAugmentationOffset)
373 "parsing augmentation data at 0x%" PRIx64
374 " failed",
375 StartOffset);
376 }
377 } else {
378 InitialLocation = Data.getRelocatedAddress(&Offset);
379 AddressRange = Data.getRelocatedAddress(&Offset);
380 }
381
382 Entries.emplace_back(new FDE(IsDWARF64, StartOffset, Length, CIEPointer,
383 InitialLocation, AddressRange, Cie,
384 LSDAAddress, Arch));
385 }
386
387 if (Error E =
388 Entries.back()->cfis().parse(Data, &Offset, EndStructureOffset))
389 return E;
390
391 if (Offset != EndStructureOffset)
392 return createStringError(
394 "parsing entry instructions at 0x%" PRIx64 " failed", StartOffset);
395 }
396
397 return Error::success();
398}
399
400FrameEntry *DWARFDebugFrame::getEntryAtOffset(uint64_t Offset) const {
401 auto It = partition_point(Entries, [=](const std::unique_ptr<FrameEntry> &E) {
402 return E->getOffset() < Offset;
403 });
404 if (It != Entries.end() && (*It)->getOffset() == Offset)
405 return It->get();
406 return nullptr;
407}
408
410 std::optional<uint64_t> Offset) const {
411 DumpOpts.IsEH = IsEH;
412 if (Offset) {
413 if (auto *Entry = getEntryAtOffset(*Offset))
414 Entry->dump(OS, DumpOpts);
415 return;
416 }
417
418 OS << "\n";
419 for (const auto &Entry : Entries)
420 Entry->dump(OS, DumpOpts);
421}
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)
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
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
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
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