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 | |
32 | using namespace llvm; |
33 | using namespace dwarf; |
34 | |
35 | static 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 | |
47 | UnwindLocation UnwindLocation::createUnspecified() { return {Unspecified}; } |
48 | |
49 | UnwindLocation UnwindLocation::createUndefined() { return {Undefined}; } |
50 | |
51 | UnwindLocation UnwindLocation::createSame() { return {Same}; } |
52 | |
53 | UnwindLocation UnwindLocation::createIsConstant(int32_t Value) { |
54 | return {Constant, InvalidRegisterNumber, Value, std::nullopt, false}; |
55 | } |
56 | |
57 | UnwindLocation UnwindLocation::createIsCFAPlusOffset(int32_t Offset) { |
58 | return {CFAPlusOffset, InvalidRegisterNumber, Offset, std::nullopt, false}; |
59 | } |
60 | |
61 | UnwindLocation UnwindLocation::createAtCFAPlusOffset(int32_t Offset) { |
62 | return {CFAPlusOffset, InvalidRegisterNumber, Offset, std::nullopt, true}; |
63 | } |
64 | |
65 | UnwindLocation |
66 | UnwindLocation::createIsRegisterPlusOffset(uint32_t RegNum, int32_t Offset, |
67 | std::optional<uint32_t> AddrSpace) { |
68 | return {RegPlusOffset, RegNum, Offset, AddrSpace, false}; |
69 | } |
70 | |
71 | UnwindLocation |
72 | UnwindLocation::createAtRegisterPlusOffset(uint32_t RegNum, int32_t Offset, |
73 | std::optional<uint32_t> AddrSpace) { |
74 | return {RegPlusOffset, RegNum, Offset, AddrSpace, true}; |
75 | } |
76 | |
77 | UnwindLocation UnwindLocation::createIsDWARFExpression(DWARFExpression Expr) { |
78 | return {Expr, false}; |
79 | } |
80 | |
81 | UnwindLocation UnwindLocation::createAtDWARFExpression(DWARFExpression Expr) { |
82 | return {Expr, true}; |
83 | } |
84 | |
85 | void 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 | |
129 | raw_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 | |
136 | bool 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 | |
157 | void 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 | |
170 | raw_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 | |
177 | void 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 | |
191 | raw_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 | |
197 | void 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 | |
203 | raw_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 | |
209 | Expected<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 | |
245 | Expected<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 | |
262 | Expected<UnwindTable::RowContainer> |
263 | llvm::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 |
576 | constexpr 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 | |
584 | void 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 | |
633 | void 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 | |
661 | DWARFDebugFrame::DWARFDebugFrame(Triple::ArchType Arch, |
662 | bool IsEH, uint64_t EHFrameAddress) |
663 | : Arch(Arch), IsEH(IsEH), EHFrameAddress(EHFrameAddress) {} |
664 | |
665 | DWARFDebugFrame::~DWARFDebugFrame() = default; |
666 | |
667 | static void LLVM_ATTRIBUTE_UNUSED (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 | |
677 | Error DWARFDebugFrame::(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 | |
876 | FrameEntry *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 | |
885 | void 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 | |