xref: /freebsd/contrib/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
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/DWARFUnwindTablePrinter.h"
19 #include "llvm/DebugInfo/DWARF/LowLevel/DWARFCFIProgram.h"
20 #include "llvm/DebugInfo/DWARF/LowLevel/DWARFExpression.h"
21 #include "llvm/Support/Compiler.h"
22 #include "llvm/Support/DataExtractor.h"
23 #include "llvm/Support/Errc.h"
24 #include "llvm/Support/Error.h"
25 #include "llvm/Support/ErrorHandling.h"
26 #include "llvm/Support/Format.h"
27 #include "llvm/Support/raw_ostream.h"
28 #include <cassert>
29 #include <cinttypes>
30 #include <cstdint>
31 #include <optional>
32 
33 using namespace llvm;
34 using namespace dwarf;
35 
36 Expected<UnwindTable> llvm::dwarf::createUnwindTable(const FDE *Fde) {
37   const CIE *Cie = Fde->getLinkedCIE();
38   if (Cie == nullptr)
39     return createStringError(errc::invalid_argument,
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 
47   UnwindTable::RowContainer CieRows;
48   UnwindRow Row;
49   Row.setAddress(Fde->getInitialLocation());
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.
54   UnwindTable::RowContainer FdeRows;
55   const RegisterLocations InitialLocs = Row.getRegisterLocations();
56   if (Error FdeError =
57           parseRows(Fde->cfis(), Row, &InitialLocs).moveInto(FdeRows))
58     return std::move(FdeError);
59 
60   UnwindTable::RowContainer AllRows;
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 
72 Expected<UnwindTable> llvm::dwarf::createUnwindTable(const CIE *Cie) {
73   // Rows will be empty if there are no CFI instructions.
74   if (Cie->cfis().empty())
75     return UnwindTable({});
76 
77   UnwindTable::RowContainer Rows;
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
93 constexpr 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 
101 void 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 {
142     DumpOpts.RecoverableErrorHandler(joinErrors(
143         createStringError(errc::invalid_argument,
144                           "decoding the CIE opcodes into rows failed"),
145         RowsOrErr.takeError()));
146   }
147   OS << "\n";
148 }
149 
150 void 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 {
170     DumpOpts.RecoverableErrorHandler(joinErrors(
171         createStringError(errc::invalid_argument,
172                           "decoding the FDE opcodes into rows failed"),
173         RowsOrErr.takeError()));
174   }
175   OS << "\n";
176 }
177 
178 DWARFDebugFrame::DWARFDebugFrame(Triple::ArchType Arch,
179     bool IsEH, uint64_t EHFrameAddress)
180     : Arch(Arch), IsEH(IsEH), EHFrameAddress(EHFrameAddress) {}
181 
182 DWARFDebugFrame::~DWARFDebugFrame() = default;
183 
184 static void LLVM_ATTRIBUTE_UNUSED dumpDataAux(DataExtractor Data,
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 
194 Error DWARFDebugFrame::parse(DWARFDataExtractor Data) {
195   uint64_t Offset = 0;
196   DenseMap<uint64_t, CIE *> CIEs;
197 
198   while (Data.isValidOffset(Offset)) {
199     uint64_t StartOffset = Offset;
200 
201     uint64_t Length;
202     DwarfFormat Format;
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(
261                 errc::invalid_argument,
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(
270                   errc::invalid_argument,
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(
287                   errc::invalid_argument,
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)
308             return createStringError(errc::invalid_argument,
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;
329       uint64_t AddressRange = 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)
336           return createStringError(errc::invalid_argument,
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.
358           if (Cie->getLSDAPointerEncoding() != DW_EH_PE_omit) {
359             LSDAAddress = Data.getEncodedPointer(
360                 &Offset, Cie->getLSDAPointerEncoding(),
361                 EHFrameAddress ? Offset + EHFrameAddress : 0);
362           }
363 
364           if (Offset != EndAugmentationOffset)
365             return createStringError(errc::invalid_argument,
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(
386           errc::invalid_argument,
387           "parsing entry instructions at 0x%" PRIx64 " failed", StartOffset);
388   }
389 
390   return Error::success();
391 }
392 
393 FrameEntry *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 
402 void DWARFDebugFrame::dump(raw_ostream &OS, DIDumpOptions DumpOpts,
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 }
415