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
9#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
10#include "llvm/ADT/DenseMap.h"
11#include "llvm/ADT/StringExtras.h"
12#include "llvm/ADT/StringRef.h"
13#include "llvm/BinaryFormat/Dwarf.h"
14#include "llvm/DebugInfo/DIContext.h"
15#include "llvm/DebugInfo/DWARF/DWARFCFIPrinter.h"
16#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
17#include "llvm/DebugInfo/DWARF/DWARFExpressionPrinter.h"
18#include "llvm/DebugInfo/DWARF/LowLevel/DWARFCFIProgram.h"
19#include "llvm/DebugInfo/DWARF/LowLevel/DWARFExpression.h"
20#include "llvm/Support/Compiler.h"
21#include "llvm/Support/DataExtractor.h"
22#include "llvm/Support/Errc.h"
23#include "llvm/Support/Error.h"
24#include "llvm/Support/ErrorHandling.h"
25#include "llvm/Support/Format.h"
26#include "llvm/Support/raw_ostream.h"
27#include <cassert>
28#include <cinttypes>
29#include <cstdint>
30#include <optional>
31
32using namespace llvm;
33using namespace dwarf;
34
35static void printRegister(raw_ostream &OS, DIDumpOptions DumpOpts,
36 unsigned RegNum) {
37 if (DumpOpts.GetNameForDWARFReg) {
38 auto RegName = DumpOpts.GetNameForDWARFReg(RegNum, DumpOpts.IsEH);
39 if (!RegName.empty()) {
40 OS << RegName;
41 return;
42 }
43 }
44 OS << "reg" << RegNum;
45}
46
47UnwindLocation UnwindLocation::createUnspecified() { return {Unspecified}; }
48
49UnwindLocation UnwindLocation::createUndefined() { return {Undefined}; }
50
51UnwindLocation UnwindLocation::createSame() { return {Same}; }
52
53UnwindLocation UnwindLocation::createIsConstant(int32_t Value) {
54 return {Constant, InvalidRegisterNumber, Value, std::nullopt, false};
55}
56
57UnwindLocation UnwindLocation::createIsCFAPlusOffset(int32_t Offset) {
58 return {CFAPlusOffset, InvalidRegisterNumber, Offset, std::nullopt, false};
59}
60
61UnwindLocation UnwindLocation::createAtCFAPlusOffset(int32_t Offset) {
62 return {CFAPlusOffset, InvalidRegisterNumber, Offset, std::nullopt, true};
63}
64
65UnwindLocation
66UnwindLocation::createIsRegisterPlusOffset(uint32_t RegNum, int32_t Offset,
67 std::optional<uint32_t> AddrSpace) {
68 return {RegPlusOffset, RegNum, Offset, AddrSpace, false};
69}
70
71UnwindLocation
72UnwindLocation::createAtRegisterPlusOffset(uint32_t RegNum, int32_t Offset,
73 std::optional<uint32_t> AddrSpace) {
74 return {RegPlusOffset, RegNum, Offset, AddrSpace, true};
75}
76
77UnwindLocation UnwindLocation::createIsDWARFExpression(DWARFExpression Expr) {
78 return {Expr, false};
79}
80
81UnwindLocation UnwindLocation::createAtDWARFExpression(DWARFExpression Expr) {
82 return {Expr, true};
83}
84
85void UnwindLocation::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
86 if (Dereference)
87 OS << '[';
88 switch (Kind) {
89 case Unspecified:
90 OS << "unspecified";
91 break;
92 case Undefined:
93 OS << "undefined";
94 break;
95 case Same:
96 OS << "same";
97 break;
98 case CFAPlusOffset:
99 OS << "CFA";
100 if (Offset == 0)
101 break;
102 if (Offset > 0)
103 OS << "+";
104 OS << Offset;
105 break;
106 case RegPlusOffset:
107 printRegister(OS, DumpOpts, RegNum);
108 if (Offset == 0 && !AddrSpace)
109 break;
110 if (Offset >= 0)
111 OS << "+";
112 OS << Offset;
113 if (AddrSpace)
114 OS << " in addrspace" << *AddrSpace;
115 break;
116 case DWARFExpr: {
117 if (Expr)
118 printDwarfExpression(E: &Expr.value(), OS, DumpOpts, U: nullptr);
119 break;
120 }
121 case Constant:
122 OS << Offset;
123 break;
124 }
125 if (Dereference)
126 OS << ']';
127}
128
129raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS,
130 const UnwindLocation &UL) {
131 auto DumpOpts = DIDumpOptions();
132 UL.dump(OS, DumpOpts);
133 return OS;
134}
135
136bool UnwindLocation::operator==(const UnwindLocation &RHS) const {
137 if (Kind != RHS.Kind)
138 return false;
139 switch (Kind) {
140 case Unspecified:
141 case Undefined:
142 case Same:
143 return true;
144 case CFAPlusOffset:
145 return Offset == RHS.Offset && Dereference == RHS.Dereference;
146 case RegPlusOffset:
147 return RegNum == RHS.RegNum && Offset == RHS.Offset &&
148 Dereference == RHS.Dereference;
149 case DWARFExpr:
150 return *Expr == *RHS.Expr && Dereference == RHS.Dereference;
151 case Constant:
152 return Offset == RHS.Offset;
153 }
154 return false;
155}
156
157void RegisterLocations::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
158 bool First = true;
159 for (const auto &RegLocPair : Locations) {
160 if (First)
161 First = false;
162 else
163 OS << ", ";
164 printRegister(OS, DumpOpts, RegNum: RegLocPair.first);
165 OS << '=';
166 RegLocPair.second.dump(OS, DumpOpts);
167 }
168}
169
170raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS,
171 const RegisterLocations &RL) {
172 auto DumpOpts = DIDumpOptions();
173 RL.dump(OS, DumpOpts);
174 return OS;
175}
176
177void UnwindRow::dump(raw_ostream &OS, DIDumpOptions DumpOpts,
178 unsigned IndentLevel) const {
179 OS.indent(NumSpaces: 2 * IndentLevel);
180 if (hasAddress())
181 OS << format(Fmt: "0x%" PRIx64 ": ", Vals: *Address);
182 OS << "CFA=";
183 CFAValue.dump(OS, DumpOpts);
184 if (RegLocs.hasLocations()) {
185 OS << ": ";
186 RegLocs.dump(OS, DumpOpts);
187 }
188 OS << "\n";
189}
190
191raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS, const UnwindRow &Row) {
192 auto DumpOpts = DIDumpOptions();
193 Row.dump(OS, DumpOpts, IndentLevel: 0);
194 return OS;
195}
196
197void UnwindTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts,
198 unsigned IndentLevel) const {
199 for (const UnwindRow &Row : Rows)
200 Row.dump(OS, DumpOpts, IndentLevel);
201}
202
203raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS, const UnwindTable &Rows) {
204 auto DumpOpts = DIDumpOptions();
205 Rows.dump(OS, DumpOpts, IndentLevel: 0);
206 return OS;
207}
208
209Expected<UnwindTable> llvm::dwarf::createUnwindTable(const FDE *Fde) {
210 const CIE *Cie = Fde->getLinkedCIE();
211 if (Cie == nullptr)
212 return createStringError(EC: errc::invalid_argument,
213 Fmt: "unable to get CIE for FDE at offset 0x%" PRIx64,
214 Vals: Fde->getOffset());
215
216 // Rows will be empty if there are no CFI instructions.
217 if (Cie->cfis().empty() && Fde->cfis().empty())
218 return UnwindTable({});
219
220 UnwindTable::RowContainer CieRows;
221 UnwindRow Row;
222 Row.setAddress(Fde->getInitialLocation());
223 if (Error CieError = parseRows(CFIP: Cie->cfis(), CurrRow&: Row, InitialLocs: nullptr).moveInto(Value&: CieRows))
224 return std::move(CieError);
225 // We need to save the initial locations of registers from the CIE parsing
226 // in case we run into DW_CFA_restore or DW_CFA_restore_extended opcodes.
227 UnwindTable::RowContainer FdeRows;
228 const RegisterLocations InitialLocs = Row.getRegisterLocations();
229 if (Error FdeError =
230 parseRows(CFIP: Fde->cfis(), CurrRow&: Row, InitialLocs: &InitialLocs).moveInto(Value&: FdeRows))
231 return std::move(FdeError);
232
233 UnwindTable::RowContainer AllRows;
234 AllRows.insert(position: AllRows.end(), first: CieRows.begin(), last: CieRows.end());
235 AllRows.insert(position: AllRows.end(), first: FdeRows.begin(), last: FdeRows.end());
236
237 // May be all the CFI instructions were DW_CFA_nop amd Row becomes empty.
238 // Do not add that to the unwind table.
239 if (Row.getRegisterLocations().hasLocations() ||
240 Row.getCFAValue().getLocation() != UnwindLocation::Unspecified)
241 AllRows.push_back(x: Row);
242 return UnwindTable(std::move(AllRows));
243}
244
245Expected<UnwindTable> llvm::dwarf::createUnwindTable(const CIE *Cie) {
246 // Rows will be empty if there are no CFI instructions.
247 if (Cie->cfis().empty())
248 return UnwindTable({});
249
250 UnwindTable::RowContainer Rows;
251 UnwindRow Row;
252 if (Error CieError = parseRows(CFIP: Cie->cfis(), CurrRow&: Row, InitialLocs: nullptr).moveInto(Value&: Rows))
253 return std::move(CieError);
254 // May be all the CFI instructions were DW_CFA_nop amd Row becomes empty.
255 // Do not add that to the unwind table.
256 if (Row.getRegisterLocations().hasLocations() ||
257 Row.getCFAValue().getLocation() != UnwindLocation::Unspecified)
258 Rows.push_back(x: Row);
259 return UnwindTable(std::move(Rows));
260}
261
262Expected<UnwindTable::RowContainer>
263llvm::dwarf::parseRows(const CFIProgram &CFIP, UnwindRow &Row,
264 const RegisterLocations *InitialLocs) {
265 // All the unwinding rows parsed during processing of the CFI program.
266 UnwindTable::RowContainer Rows;
267
268 // State consists of CFA value and register locations.
269 std::vector<std::pair<UnwindLocation, RegisterLocations>> States;
270 for (const CFIProgram::Instruction &Inst : CFIP) {
271 switch (Inst.Opcode) {
272 case dwarf::DW_CFA_set_loc: {
273 // The DW_CFA_set_loc instruction takes a single operand that
274 // represents a target address. The required action is to create a new
275 // table row using the specified address as the location. All other
276 // values in the new row are initially identical to the current row.
277 // The new location value is always greater than the current one. If
278 // the segment_size field of this FDE's CIE is non- zero, the initial
279 // location is preceded by a segment selector of the given length
280 llvm::Expected<uint64_t> NewAddress = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 0);
281 if (!NewAddress)
282 return NewAddress.takeError();
283 if (*NewAddress <= Row.getAddress())
284 return createStringError(
285 EC: errc::invalid_argument,
286 Fmt: "%s with adrress 0x%" PRIx64 " which must be greater than the "
287 "current row address 0x%" PRIx64,
288 Vals: CFIP.callFrameString(Opcode: Inst.Opcode).str().c_str(), Vals: *NewAddress,
289 Vals: Row.getAddress());
290 Rows.push_back(x: Row);
291 Row.setAddress(*NewAddress);
292 break;
293 }
294
295 case dwarf::DW_CFA_advance_loc:
296 case dwarf::DW_CFA_advance_loc1:
297 case dwarf::DW_CFA_advance_loc2:
298 case dwarf::DW_CFA_advance_loc4: {
299 // The DW_CFA_advance instruction takes a single operand that
300 // represents a constant delta. The required action is to create a new
301 // table row with a location value that is computed by taking the
302 // current entry’s location value and adding the value of delta *
303 // code_alignment_factor. All other values in the new row are initially
304 // identical to the current row.
305 Rows.push_back(x: Row);
306 llvm::Expected<uint64_t> Offset = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 0);
307 if (!Offset)
308 return Offset.takeError();
309 Row.slideAddress(Offset: *Offset);
310 break;
311 }
312
313 case dwarf::DW_CFA_restore:
314 case dwarf::DW_CFA_restore_extended: {
315 // The DW_CFA_restore instruction takes a single operand (encoded with
316 // the opcode) that represents a register number. The required action
317 // is to change the rule for the indicated register to the rule
318 // assigned it by the initial_instructions in the CIE.
319 if (InitialLocs == nullptr)
320 return createStringError(
321 EC: errc::invalid_argument, Fmt: "%s encountered while parsing a CIE",
322 Vals: CFIP.callFrameString(Opcode: Inst.Opcode).str().c_str());
323 llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 0);
324 if (!RegNum)
325 return RegNum.takeError();
326 if (std::optional<UnwindLocation> O =
327 InitialLocs->getRegisterLocation(RegNum: *RegNum))
328 Row.getRegisterLocations().setRegisterLocation(RegNum: *RegNum, Location: *O);
329 else
330 Row.getRegisterLocations().removeRegisterLocation(RegNum: *RegNum);
331 break;
332 }
333
334 case dwarf::DW_CFA_offset:
335 case dwarf::DW_CFA_offset_extended:
336 case dwarf::DW_CFA_offset_extended_sf: {
337 llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 0);
338 if (!RegNum)
339 return RegNum.takeError();
340 llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, OperandIdx: 1);
341 if (!Offset)
342 return Offset.takeError();
343 Row.getRegisterLocations().setRegisterLocation(
344 RegNum: *RegNum, Location: UnwindLocation::createAtCFAPlusOffset(Offset: *Offset));
345 break;
346 }
347
348 case dwarf::DW_CFA_nop:
349 break;
350
351 case dwarf::DW_CFA_remember_state:
352 States.push_back(
353 x: std::make_pair(x&: Row.getCFAValue(), y&: Row.getRegisterLocations()));
354 break;
355
356 case dwarf::DW_CFA_restore_state:
357 if (States.empty())
358 return createStringError(EC: errc::invalid_argument,
359 S: "DW_CFA_restore_state without a matching "
360 "previous DW_CFA_remember_state");
361 Row.getCFAValue() = States.back().first;
362 Row.getRegisterLocations() = States.back().second;
363 States.pop_back();
364 break;
365
366 case dwarf::DW_CFA_GNU_window_save:
367 switch (CFIP.triple()) {
368 case Triple::aarch64:
369 case Triple::aarch64_be:
370 case Triple::aarch64_32: {
371 // DW_CFA_GNU_window_save is used for different things on different
372 // architectures. For aarch64 it is known as
373 // DW_CFA_AARCH64_negate_ra_state. The action is to toggle the
374 // value of the return address state between 1 and 0. If there is
375 // no rule for the AARCH64_DWARF_PAUTH_RA_STATE register, then it
376 // should be initially set to 1.
377 constexpr uint32_t AArch64DWARFPAuthRaState = 34;
378 auto LRLoc = Row.getRegisterLocations().getRegisterLocation(
379 RegNum: AArch64DWARFPAuthRaState);
380 if (LRLoc) {
381 if (LRLoc->getLocation() == UnwindLocation::Constant) {
382 // Toggle the constant value from 0 to 1 or 1 to 0.
383 LRLoc->setConstant(LRLoc->getConstant() ^ 1);
384 Row.getRegisterLocations().setRegisterLocation(
385 RegNum: AArch64DWARFPAuthRaState, Location: *LRLoc);
386 } else {
387 return createStringError(
388 EC: errc::invalid_argument,
389 Fmt: "%s encountered when existing rule for this register is not "
390 "a constant",
391 Vals: CFIP.callFrameString(Opcode: Inst.Opcode).str().c_str());
392 }
393 } else {
394 Row.getRegisterLocations().setRegisterLocation(
395 RegNum: AArch64DWARFPAuthRaState, Location: UnwindLocation::createIsConstant(Value: 1));
396 }
397 break;
398 }
399
400 case Triple::sparc:
401 case Triple::sparcv9:
402 case Triple::sparcel:
403 for (uint32_t RegNum = 16; RegNum < 32; ++RegNum) {
404 Row.getRegisterLocations().setRegisterLocation(
405 RegNum, Location: UnwindLocation::createAtCFAPlusOffset(Offset: (RegNum - 16) * 8));
406 }
407 break;
408
409 default: {
410 return createStringError(
411 EC: errc::not_supported,
412 Fmt: "DW_CFA opcode %#x is not supported for architecture %s",
413 Vals: Inst.Opcode, Vals: Triple::getArchTypeName(Kind: CFIP.triple()).str().c_str());
414
415 break;
416 }
417 }
418 break;
419
420 case dwarf::DW_CFA_AARCH64_negate_ra_state_with_pc: {
421 constexpr uint32_t AArch64DWARFPAuthRaState = 34;
422 auto LRLoc = Row.getRegisterLocations().getRegisterLocation(
423 RegNum: AArch64DWARFPAuthRaState);
424 if (LRLoc) {
425 if (LRLoc->getLocation() == UnwindLocation::Constant) {
426 // Toggle the constant value of bits[1:0] from 0 to 1 or 1 to 0.
427 LRLoc->setConstant(LRLoc->getConstant() ^ 0x3);
428 } else {
429 return createStringError(
430 EC: errc::invalid_argument,
431 Fmt: "%s encountered when existing rule for this register is not "
432 "a constant",
433 Vals: CFIP.callFrameString(Opcode: Inst.Opcode).str().c_str());
434 }
435 } else {
436 Row.getRegisterLocations().setRegisterLocation(
437 RegNum: AArch64DWARFPAuthRaState, Location: UnwindLocation::createIsConstant(Value: 0x3));
438 }
439 break;
440 }
441
442 case dwarf::DW_CFA_undefined: {
443 llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 0);
444 if (!RegNum)
445 return RegNum.takeError();
446 Row.getRegisterLocations().setRegisterLocation(
447 RegNum: *RegNum, Location: UnwindLocation::createUndefined());
448 break;
449 }
450
451 case dwarf::DW_CFA_same_value: {
452 llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 0);
453 if (!RegNum)
454 return RegNum.takeError();
455 Row.getRegisterLocations().setRegisterLocation(
456 RegNum: *RegNum, Location: UnwindLocation::createSame());
457 break;
458 }
459
460 case dwarf::DW_CFA_GNU_args_size:
461 break;
462
463 case dwarf::DW_CFA_register: {
464 llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 0);
465 if (!RegNum)
466 return RegNum.takeError();
467 llvm::Expected<uint64_t> NewRegNum = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 1);
468 if (!NewRegNum)
469 return NewRegNum.takeError();
470 Row.getRegisterLocations().setRegisterLocation(
471 RegNum: *RegNum, Location: UnwindLocation::createIsRegisterPlusOffset(RegNum: *NewRegNum, Offset: 0));
472 break;
473 }
474
475 case dwarf::DW_CFA_val_offset:
476 case dwarf::DW_CFA_val_offset_sf: {
477 llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 0);
478 if (!RegNum)
479 return RegNum.takeError();
480 llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, OperandIdx: 1);
481 if (!Offset)
482 return Offset.takeError();
483 Row.getRegisterLocations().setRegisterLocation(
484 RegNum: *RegNum, Location: UnwindLocation::createIsCFAPlusOffset(Offset: *Offset));
485 break;
486 }
487
488 case dwarf::DW_CFA_expression: {
489 llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 0);
490 if (!RegNum)
491 return RegNum.takeError();
492 Row.getRegisterLocations().setRegisterLocation(
493 RegNum: *RegNum, Location: UnwindLocation::createAtDWARFExpression(Expr: *Inst.Expression));
494 break;
495 }
496
497 case dwarf::DW_CFA_val_expression: {
498 llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 0);
499 if (!RegNum)
500 return RegNum.takeError();
501 Row.getRegisterLocations().setRegisterLocation(
502 RegNum: *RegNum, Location: UnwindLocation::createIsDWARFExpression(Expr: *Inst.Expression));
503 break;
504 }
505
506 case dwarf::DW_CFA_def_cfa_register: {
507 llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 0);
508 if (!RegNum)
509 return RegNum.takeError();
510 if (Row.getCFAValue().getLocation() != UnwindLocation::RegPlusOffset)
511 Row.getCFAValue() =
512 UnwindLocation::createIsRegisterPlusOffset(RegNum: *RegNum, Offset: 0);
513 else
514 Row.getCFAValue().setRegister(*RegNum);
515 break;
516 }
517
518 case dwarf::DW_CFA_def_cfa_offset:
519 case dwarf::DW_CFA_def_cfa_offset_sf: {
520 llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, OperandIdx: 0);
521 if (!Offset)
522 return Offset.takeError();
523 if (Row.getCFAValue().getLocation() != UnwindLocation::RegPlusOffset) {
524 return createStringError(
525 EC: errc::invalid_argument,
526 Fmt: "%s found when CFA rule was not RegPlusOffset",
527 Vals: CFIP.callFrameString(Opcode: Inst.Opcode).str().c_str());
528 }
529 Row.getCFAValue().setOffset(*Offset);
530 break;
531 }
532
533 case dwarf::DW_CFA_def_cfa:
534 case dwarf::DW_CFA_def_cfa_sf: {
535 llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 0);
536 if (!RegNum)
537 return RegNum.takeError();
538 llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, OperandIdx: 1);
539 if (!Offset)
540 return Offset.takeError();
541 Row.getCFAValue() =
542 UnwindLocation::createIsRegisterPlusOffset(RegNum: *RegNum, Offset: *Offset);
543 break;
544 }
545
546 case dwarf::DW_CFA_LLVM_def_aspace_cfa:
547 case dwarf::DW_CFA_LLVM_def_aspace_cfa_sf: {
548 llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 0);
549 if (!RegNum)
550 return RegNum.takeError();
551 llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, OperandIdx: 1);
552 if (!Offset)
553 return Offset.takeError();
554 llvm::Expected<uint32_t> CFAAddrSpace =
555 Inst.getOperandAsUnsigned(CFIP, OperandIdx: 2);
556 if (!CFAAddrSpace)
557 return CFAAddrSpace.takeError();
558 Row.getCFAValue() = UnwindLocation::createIsRegisterPlusOffset(
559 RegNum: *RegNum, Offset: *Offset, AddrSpace: *CFAAddrSpace);
560 break;
561 }
562
563 case dwarf::DW_CFA_def_cfa_expression:
564 Row.getCFAValue() =
565 UnwindLocation::createIsDWARFExpression(Expr: *Inst.Expression);
566 break;
567 }
568 }
569 return Rows;
570}
571
572// Returns the CIE identifier to be used by the requested format.
573// CIE ids for .debug_frame sections are defined in Section 7.24 of DWARFv5.
574// For CIE ID in .eh_frame sections see
575// https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
576constexpr uint64_t getCIEId(bool IsDWARF64, bool IsEH) {
577 if (IsEH)
578 return 0;
579 if (IsDWARF64)
580 return DW64_CIE_ID;
581 return DW_CIE_ID;
582}
583
584void CIE::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
585 // A CIE with a zero length is a terminator entry in the .eh_frame section.
586 if (DumpOpts.IsEH && Length == 0) {
587 OS << format(Fmt: "%08" PRIx64, Vals: Offset) << " ZERO terminator\n";
588 return;
589 }
590
591 OS << format(Fmt: "%08" PRIx64, Vals: Offset)
592 << format(Fmt: " %0*" PRIx64, Vals: IsDWARF64 ? 16 : 8, Vals: Length)
593 << format(Fmt: " %0*" PRIx64, Vals: IsDWARF64 && !DumpOpts.IsEH ? 16 : 8,
594 Vals: getCIEId(IsDWARF64, IsEH: DumpOpts.IsEH))
595 << " CIE\n"
596 << " Format: " << FormatString(IsDWARF64) << "\n";
597 if (DumpOpts.IsEH && Version != 1)
598 OS << "WARNING: unsupported CIE version\n";
599 OS << format(Fmt: " Version: %d\n", Vals: Version)
600 << " Augmentation: \"" << Augmentation << "\"\n";
601 if (Version >= 4) {
602 OS << format(Fmt: " Address size: %u\n", Vals: (uint32_t)AddressSize);
603 OS << format(Fmt: " Segment desc size: %u\n",
604 Vals: (uint32_t)SegmentDescriptorSize);
605 }
606 OS << format(Fmt: " Code alignment factor: %u\n", Vals: (uint32_t)CodeAlignmentFactor);
607 OS << format(Fmt: " Data alignment factor: %d\n", Vals: (int32_t)DataAlignmentFactor);
608 OS << format(Fmt: " Return address column: %d\n", Vals: (int32_t)ReturnAddressRegister);
609 if (Personality)
610 OS << format(Fmt: " Personality Address: %016" PRIx64 "\n", Vals: *Personality);
611 if (!AugmentationData.empty()) {
612 OS << " Augmentation data: ";
613 for (uint8_t Byte : AugmentationData)
614 OS << ' ' << hexdigit(X: Byte >> 4) << hexdigit(X: Byte & 0xf);
615 OS << "\n";
616 }
617 OS << "\n";
618 printCFIProgram(P: CFIs, OS, DumpOpts, /*IndentLevel=*/1,
619 /*InitialLocation=*/Address: {});
620 OS << "\n";
621
622 if (Expected<UnwindTable> RowsOrErr = createUnwindTable(Cie: this))
623 RowsOrErr->dump(OS, DumpOpts, IndentLevel: 1);
624 else {
625 DumpOpts.RecoverableErrorHandler(joinErrors(
626 E1: createStringError(EC: errc::invalid_argument,
627 S: "decoding the CIE opcodes into rows failed"),
628 E2: RowsOrErr.takeError()));
629 }
630 OS << "\n";
631}
632
633void FDE::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
634 OS << format(Fmt: "%08" PRIx64, Vals: Offset)
635 << format(Fmt: " %0*" PRIx64, Vals: IsDWARF64 ? 16 : 8, Vals: Length)
636 << format(Fmt: " %0*" PRIx64, Vals: IsDWARF64 && !DumpOpts.IsEH ? 16 : 8, Vals: CIEPointer)
637 << " FDE cie=";
638 if (LinkedCIE)
639 OS << format(Fmt: "%08" PRIx64, Vals: LinkedCIE->getOffset());
640 else
641 OS << "<invalid offset>";
642 OS << format(Fmt: " pc=%08" PRIx64 "...%08" PRIx64 "\n", Vals: InitialLocation,
643 Vals: InitialLocation + AddressRange);
644 OS << " Format: " << FormatString(IsDWARF64) << "\n";
645 if (LSDAAddress)
646 OS << format(Fmt: " LSDA Address: %016" PRIx64 "\n", Vals: *LSDAAddress);
647 printCFIProgram(P: CFIs, OS, DumpOpts, /*IndentLevel=*/1, Address: InitialLocation);
648 OS << "\n";
649
650 if (Expected<UnwindTable> RowsOrErr = createUnwindTable(Fde: this))
651 RowsOrErr->dump(OS, DumpOpts, IndentLevel: 1);
652 else {
653 DumpOpts.RecoverableErrorHandler(joinErrors(
654 E1: createStringError(EC: errc::invalid_argument,
655 S: "decoding the FDE opcodes into rows failed"),
656 E2: RowsOrErr.takeError()));
657 }
658 OS << "\n";
659}
660
661DWARFDebugFrame::DWARFDebugFrame(Triple::ArchType Arch,
662 bool IsEH, uint64_t EHFrameAddress)
663 : Arch(Arch), IsEH(IsEH), EHFrameAddress(EHFrameAddress) {}
664
665DWARFDebugFrame::~DWARFDebugFrame() = default;
666
667static void LLVM_ATTRIBUTE_UNUSED dumpDataAux(DataExtractor Data,
668 uint64_t Offset, int Length) {
669 errs() << "DUMP: ";
670 for (int i = 0; i < Length; ++i) {
671 uint8_t c = Data.getU8(offset_ptr: &Offset);
672 errs().write_hex(N: c); errs() << " ";
673 }
674 errs() << "\n";
675}
676
677Error DWARFDebugFrame::parse(DWARFDataExtractor Data) {
678 uint64_t Offset = 0;
679 DenseMap<uint64_t, CIE *> CIEs;
680
681 while (Data.isValidOffset(offset: Offset)) {
682 uint64_t StartOffset = Offset;
683
684 uint64_t Length;
685 DwarfFormat Format;
686 std::tie(args&: Length, args&: Format) = Data.getInitialLength(Off: &Offset);
687 bool IsDWARF64 = Format == DWARF64;
688
689 // If the Length is 0, then this CIE is a terminator. We add it because some
690 // dumper tools might need it to print something special for such entries
691 // (e.g. llvm-objdump --dwarf=frames prints "ZERO terminator").
692 if (Length == 0) {
693 auto Cie = std::make_unique<CIE>(
694 args&: IsDWARF64, args&: StartOffset, args: 0, args: 0, args: SmallString<8>(), args: 0, args: 0, args: 0, args: 0, args: 0,
695 args: SmallString<8>(), args: 0, args: 0, args: std::nullopt, args: std::nullopt, args: Arch);
696 CIEs[StartOffset] = Cie.get();
697 Entries.push_back(x: std::move(Cie));
698 break;
699 }
700
701 // At this point, Offset points to the next field after Length.
702 // Length is the structure size excluding itself. Compute an offset one
703 // past the end of the structure (needed to know how many instructions to
704 // read).
705 uint64_t StartStructureOffset = Offset;
706 uint64_t EndStructureOffset = Offset + Length;
707
708 // The Id field's size depends on the DWARF format
709 Error Err = Error::success();
710 uint64_t Id = Data.getRelocatedValue(Size: (IsDWARF64 && !IsEH) ? 8 : 4, Off: &Offset,
711 /*SectionIndex=*/nullptr, Err: &Err);
712 if (Err)
713 return Err;
714
715 if (Id == getCIEId(IsDWARF64, IsEH)) {
716 uint8_t Version = Data.getU8(offset_ptr: &Offset);
717 const char *Augmentation = Data.getCStr(OffsetPtr: &Offset);
718 StringRef AugmentationString(Augmentation ? Augmentation : "");
719 uint8_t AddressSize = Version < 4 ? Data.getAddressSize() :
720 Data.getU8(offset_ptr: &Offset);
721 Data.setAddressSize(AddressSize);
722 uint8_t SegmentDescriptorSize = Version < 4 ? 0 : Data.getU8(offset_ptr: &Offset);
723 uint64_t CodeAlignmentFactor = Data.getULEB128(offset_ptr: &Offset);
724 int64_t DataAlignmentFactor = Data.getSLEB128(OffsetPtr: &Offset);
725 uint64_t ReturnAddressRegister =
726 Version == 1 ? Data.getU8(offset_ptr: &Offset) : Data.getULEB128(offset_ptr: &Offset);
727
728 // Parse the augmentation data for EH CIEs
729 StringRef AugmentationData("");
730 uint32_t FDEPointerEncoding = DW_EH_PE_absptr;
731 uint32_t LSDAPointerEncoding = DW_EH_PE_omit;
732 std::optional<uint64_t> Personality;
733 std::optional<uint32_t> PersonalityEncoding;
734 if (IsEH) {
735 std::optional<uint64_t> AugmentationLength;
736 uint64_t StartAugmentationOffset;
737 uint64_t EndAugmentationOffset;
738
739 // Walk the augmentation string to get all the augmentation data.
740 for (unsigned i = 0, e = AugmentationString.size(); i != e; ++i) {
741 switch (AugmentationString[i]) {
742 default:
743 return createStringError(
744 EC: errc::invalid_argument,
745 Fmt: "unknown augmentation character %c in entry at 0x%" PRIx64,
746 Vals: AugmentationString[i], Vals: StartOffset);
747 case 'L':
748 LSDAPointerEncoding = Data.getU8(offset_ptr: &Offset);
749 break;
750 case 'P': {
751 if (Personality)
752 return createStringError(
753 EC: errc::invalid_argument,
754 Fmt: "duplicate personality in entry at 0x%" PRIx64, Vals: StartOffset);
755 PersonalityEncoding = Data.getU8(offset_ptr: &Offset);
756 Personality = Data.getEncodedPointer(
757 Offset: &Offset, Encoding: *PersonalityEncoding,
758 PCRelOffset: EHFrameAddress ? EHFrameAddress + Offset : 0);
759 break;
760 }
761 case 'R':
762 FDEPointerEncoding = Data.getU8(offset_ptr: &Offset);
763 break;
764 case 'S':
765 // Current frame is a signal trampoline.
766 break;
767 case 'z':
768 if (i)
769 return createStringError(
770 EC: errc::invalid_argument,
771 Fmt: "'z' must be the first character at 0x%" PRIx64, Vals: StartOffset);
772 // Parse the augmentation length first. We only parse it if
773 // the string contains a 'z'.
774 AugmentationLength = Data.getULEB128(offset_ptr: &Offset);
775 StartAugmentationOffset = Offset;
776 EndAugmentationOffset = Offset + *AugmentationLength;
777 break;
778 case 'B':
779 // B-Key is used for signing functions associated with this
780 // augmentation string
781 break;
782 // This stack frame contains MTE tagged data, so needs to be
783 // untagged on unwind.
784 case 'G':
785 break;
786 }
787 }
788
789 if (AugmentationLength) {
790 if (Offset != EndAugmentationOffset)
791 return createStringError(EC: errc::invalid_argument,
792 Fmt: "parsing augmentation data at 0x%" PRIx64
793 " failed",
794 Vals: StartOffset);
795 AugmentationData = Data.getData().slice(Start: StartAugmentationOffset,
796 End: EndAugmentationOffset);
797 }
798 }
799
800 auto Cie = std::make_unique<CIE>(
801 args&: IsDWARF64, args&: StartOffset, args&: Length, args&: Version, args&: AugmentationString,
802 args&: AddressSize, args&: SegmentDescriptorSize, args&: CodeAlignmentFactor,
803 args&: DataAlignmentFactor, args&: ReturnAddressRegister, args&: AugmentationData,
804 args&: FDEPointerEncoding, args&: LSDAPointerEncoding, args&: Personality,
805 args&: PersonalityEncoding, args: Arch);
806 CIEs[StartOffset] = Cie.get();
807 Entries.emplace_back(args: std::move(Cie));
808 } else {
809 // FDE
810 uint64_t CIEPointer = Id;
811 uint64_t InitialLocation = 0;
812 uint64_t AddressRange = 0;
813 std::optional<uint64_t> LSDAAddress;
814 CIE *Cie = CIEs[IsEH ? (StartStructureOffset - CIEPointer) : CIEPointer];
815
816 if (IsEH) {
817 // The address size is encoded in the CIE we reference.
818 if (!Cie)
819 return createStringError(EC: errc::invalid_argument,
820 Fmt: "parsing FDE data at 0x%" PRIx64
821 " failed due to missing CIE",
822 Vals: StartOffset);
823 if (auto Val =
824 Data.getEncodedPointer(Offset: &Offset, Encoding: Cie->getFDEPointerEncoding(),
825 PCRelOffset: EHFrameAddress + Offset)) {
826 InitialLocation = *Val;
827 }
828 if (auto Val = Data.getEncodedPointer(
829 Offset: &Offset, Encoding: Cie->getFDEPointerEncoding(), PCRelOffset: 0)) {
830 AddressRange = *Val;
831 }
832
833 StringRef AugmentationString = Cie->getAugmentationString();
834 if (!AugmentationString.empty()) {
835 // Parse the augmentation length and data for this FDE.
836 uint64_t AugmentationLength = Data.getULEB128(offset_ptr: &Offset);
837
838 uint64_t EndAugmentationOffset = Offset + AugmentationLength;
839
840 // Decode the LSDA if the CIE augmentation string said we should.
841 if (Cie->getLSDAPointerEncoding() != DW_EH_PE_omit) {
842 LSDAAddress = Data.getEncodedPointer(
843 Offset: &Offset, Encoding: Cie->getLSDAPointerEncoding(),
844 PCRelOffset: EHFrameAddress ? Offset + EHFrameAddress : 0);
845 }
846
847 if (Offset != EndAugmentationOffset)
848 return createStringError(EC: errc::invalid_argument,
849 Fmt: "parsing augmentation data at 0x%" PRIx64
850 " failed",
851 Vals: StartOffset);
852 }
853 } else {
854 InitialLocation = Data.getRelocatedAddress(Off: &Offset);
855 AddressRange = Data.getRelocatedAddress(Off: &Offset);
856 }
857
858 Entries.emplace_back(args: new FDE(IsDWARF64, StartOffset, Length, CIEPointer,
859 InitialLocation, AddressRange, Cie,
860 LSDAAddress, Arch));
861 }
862
863 if (Error E =
864 Entries.back()->cfis().parse(Data, Offset: &Offset, EndOffset: EndStructureOffset))
865 return E;
866
867 if (Offset != EndStructureOffset)
868 return createStringError(
869 EC: errc::invalid_argument,
870 Fmt: "parsing entry instructions at 0x%" PRIx64 " failed", Vals: StartOffset);
871 }
872
873 return Error::success();
874}
875
876FrameEntry *DWARFDebugFrame::getEntryAtOffset(uint64_t Offset) const {
877 auto It = partition_point(Range: Entries, P: [=](const std::unique_ptr<FrameEntry> &E) {
878 return E->getOffset() < Offset;
879 });
880 if (It != Entries.end() && (*It)->getOffset() == Offset)
881 return It->get();
882 return nullptr;
883}
884
885void DWARFDebugFrame::dump(raw_ostream &OS, DIDumpOptions DumpOpts,
886 std::optional<uint64_t> Offset) const {
887 DumpOpts.IsEH = IsEH;
888 if (Offset) {
889 if (auto *Entry = getEntryAtOffset(Offset: *Offset))
890 Entry->dump(OS, DumpOpts);
891 return;
892 }
893
894 OS << "\n";
895 for (const auto &Entry : Entries)
896 Entry->dump(OS, DumpOpts);
897}
898