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/DWARFDataExtractor.h" |
16 | #include "llvm/Support/Compiler.h" |
17 | #include "llvm/Support/DataExtractor.h" |
18 | #include "llvm/Support/Errc.h" |
19 | #include "llvm/Support/ErrorHandling.h" |
20 | #include "llvm/Support/Format.h" |
21 | #include "llvm/Support/raw_ostream.h" |
22 | #include <algorithm> |
23 | #include <cassert> |
24 | #include <cinttypes> |
25 | #include <cstdint> |
26 | #include <optional> |
27 | |
28 | using namespace llvm; |
29 | using namespace dwarf; |
30 | |
31 | static void printRegister(raw_ostream &OS, DIDumpOptions DumpOpts, |
32 | unsigned RegNum) { |
33 | if (DumpOpts.GetNameForDWARFReg) { |
34 | auto RegName = DumpOpts.GetNameForDWARFReg(RegNum, DumpOpts.IsEH); |
35 | if (!RegName.empty()) { |
36 | OS << RegName; |
37 | return; |
38 | } |
39 | } |
40 | OS << "reg" << RegNum; |
41 | } |
42 | |
43 | UnwindLocation UnwindLocation::createUnspecified() { return {Unspecified}; } |
44 | |
45 | UnwindLocation UnwindLocation::createUndefined() { return {Undefined}; } |
46 | |
47 | UnwindLocation UnwindLocation::createSame() { return {Same}; } |
48 | |
49 | UnwindLocation UnwindLocation::createIsConstant(int32_t Value) { |
50 | return {Constant, InvalidRegisterNumber, Value, std::nullopt, false}; |
51 | } |
52 | |
53 | UnwindLocation UnwindLocation::createIsCFAPlusOffset(int32_t Offset) { |
54 | return {CFAPlusOffset, InvalidRegisterNumber, Offset, std::nullopt, false}; |
55 | } |
56 | |
57 | UnwindLocation UnwindLocation::createAtCFAPlusOffset(int32_t Offset) { |
58 | return {CFAPlusOffset, InvalidRegisterNumber, Offset, std::nullopt, true}; |
59 | } |
60 | |
61 | UnwindLocation |
62 | UnwindLocation::createIsRegisterPlusOffset(uint32_t RegNum, int32_t Offset, |
63 | std::optional<uint32_t> AddrSpace) { |
64 | return {RegPlusOffset, RegNum, Offset, AddrSpace, false}; |
65 | } |
66 | |
67 | UnwindLocation |
68 | UnwindLocation::createAtRegisterPlusOffset(uint32_t RegNum, int32_t Offset, |
69 | std::optional<uint32_t> AddrSpace) { |
70 | return {RegPlusOffset, RegNum, Offset, AddrSpace, true}; |
71 | } |
72 | |
73 | UnwindLocation UnwindLocation::createIsDWARFExpression(DWARFExpression Expr) { |
74 | return {Expr, false}; |
75 | } |
76 | |
77 | UnwindLocation UnwindLocation::createAtDWARFExpression(DWARFExpression Expr) { |
78 | return {Expr, true}; |
79 | } |
80 | |
81 | void UnwindLocation::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const { |
82 | if (Dereference) |
83 | OS << '['; |
84 | switch (Kind) { |
85 | case Unspecified: |
86 | OS << "unspecified" ; |
87 | break; |
88 | case Undefined: |
89 | OS << "undefined" ; |
90 | break; |
91 | case Same: |
92 | OS << "same" ; |
93 | break; |
94 | case CFAPlusOffset: |
95 | OS << "CFA" ; |
96 | if (Offset == 0) |
97 | break; |
98 | if (Offset > 0) |
99 | OS << "+" ; |
100 | OS << Offset; |
101 | break; |
102 | case RegPlusOffset: |
103 | printRegister(OS, DumpOpts, RegNum); |
104 | if (Offset == 0 && !AddrSpace) |
105 | break; |
106 | if (Offset >= 0) |
107 | OS << "+" ; |
108 | OS << Offset; |
109 | if (AddrSpace) |
110 | OS << " in addrspace" << *AddrSpace; |
111 | break; |
112 | case DWARFExpr: { |
113 | Expr->print(OS, DumpOpts, U: nullptr); |
114 | break; |
115 | } |
116 | case Constant: |
117 | OS << Offset; |
118 | break; |
119 | } |
120 | if (Dereference) |
121 | OS << ']'; |
122 | } |
123 | |
124 | raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS, |
125 | const UnwindLocation &UL) { |
126 | auto DumpOpts = DIDumpOptions(); |
127 | UL.dump(OS, DumpOpts); |
128 | return OS; |
129 | } |
130 | |
131 | bool UnwindLocation::operator==(const UnwindLocation &RHS) const { |
132 | if (Kind != RHS.Kind) |
133 | return false; |
134 | switch (Kind) { |
135 | case Unspecified: |
136 | case Undefined: |
137 | case Same: |
138 | return true; |
139 | case CFAPlusOffset: |
140 | return Offset == RHS.Offset && Dereference == RHS.Dereference; |
141 | case RegPlusOffset: |
142 | return RegNum == RHS.RegNum && Offset == RHS.Offset && |
143 | Dereference == RHS.Dereference; |
144 | case DWARFExpr: |
145 | return *Expr == *RHS.Expr && Dereference == RHS.Dereference; |
146 | case Constant: |
147 | return Offset == RHS.Offset; |
148 | } |
149 | return false; |
150 | } |
151 | |
152 | void RegisterLocations::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const { |
153 | bool First = true; |
154 | for (const auto &RegLocPair : Locations) { |
155 | if (First) |
156 | First = false; |
157 | else |
158 | OS << ", " ; |
159 | printRegister(OS, DumpOpts, RegNum: RegLocPair.first); |
160 | OS << '='; |
161 | RegLocPair.second.dump(OS, DumpOpts); |
162 | } |
163 | } |
164 | |
165 | raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS, |
166 | const RegisterLocations &RL) { |
167 | auto DumpOpts = DIDumpOptions(); |
168 | RL.dump(OS, DumpOpts); |
169 | return OS; |
170 | } |
171 | |
172 | void UnwindRow::dump(raw_ostream &OS, DIDumpOptions DumpOpts, |
173 | unsigned IndentLevel) const { |
174 | OS.indent(NumSpaces: 2 * IndentLevel); |
175 | if (hasAddress()) |
176 | OS << format(Fmt: "0x%" PRIx64 ": " , Vals: *Address); |
177 | OS << "CFA=" ; |
178 | CFAValue.dump(OS, DumpOpts); |
179 | if (RegLocs.hasLocations()) { |
180 | OS << ": " ; |
181 | RegLocs.dump(OS, DumpOpts); |
182 | } |
183 | OS << "\n" ; |
184 | } |
185 | |
186 | raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS, const UnwindRow &Row) { |
187 | auto DumpOpts = DIDumpOptions(); |
188 | Row.dump(OS, DumpOpts, IndentLevel: 0); |
189 | return OS; |
190 | } |
191 | |
192 | void UnwindTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts, |
193 | unsigned IndentLevel) const { |
194 | for (const UnwindRow &Row : Rows) |
195 | Row.dump(OS, DumpOpts, IndentLevel); |
196 | } |
197 | |
198 | raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS, const UnwindTable &Rows) { |
199 | auto DumpOpts = DIDumpOptions(); |
200 | Rows.dump(OS, DumpOpts, IndentLevel: 0); |
201 | return OS; |
202 | } |
203 | |
204 | Expected<UnwindTable> UnwindTable::create(const FDE *Fde) { |
205 | const CIE *Cie = Fde->getLinkedCIE(); |
206 | if (Cie == nullptr) |
207 | return createStringError(EC: errc::invalid_argument, |
208 | Fmt: "unable to get CIE for FDE at offset 0x%" PRIx64, |
209 | Vals: Fde->getOffset()); |
210 | |
211 | // Rows will be empty if there are no CFI instructions. |
212 | if (Cie->cfis().empty() && Fde->cfis().empty()) |
213 | return UnwindTable(); |
214 | |
215 | UnwindTable UT; |
216 | UnwindRow Row; |
217 | Row.setAddress(Fde->getInitialLocation()); |
218 | UT.EndAddress = Fde->getInitialLocation() + Fde->getAddressRange(); |
219 | if (Error CieError = UT.parseRows(CFIP: Cie->cfis(), CurrRow&: Row, InitialLocs: nullptr)) |
220 | return std::move(CieError); |
221 | // We need to save the initial locations of registers from the CIE parsing |
222 | // in case we run into DW_CFA_restore or DW_CFA_restore_extended opcodes. |
223 | const RegisterLocations InitialLocs = Row.getRegisterLocations(); |
224 | if (Error FdeError = UT.parseRows(CFIP: Fde->cfis(), CurrRow&: Row, InitialLocs: &InitialLocs)) |
225 | return std::move(FdeError); |
226 | // May be all the CFI instructions were DW_CFA_nop amd Row becomes empty. |
227 | // Do not add that to the unwind table. |
228 | if (Row.getRegisterLocations().hasLocations() || |
229 | Row.getCFAValue().getLocation() != UnwindLocation::Unspecified) |
230 | UT.Rows.push_back(x: Row); |
231 | return UT; |
232 | } |
233 | |
234 | Expected<UnwindTable> UnwindTable::create(const CIE *Cie) { |
235 | // Rows will be empty if there are no CFI instructions. |
236 | if (Cie->cfis().empty()) |
237 | return UnwindTable(); |
238 | |
239 | UnwindTable UT; |
240 | UnwindRow Row; |
241 | if (Error CieError = UT.parseRows(CFIP: Cie->cfis(), CurrRow&: Row, InitialLocs: nullptr)) |
242 | return std::move(CieError); |
243 | // May be all the CFI instructions were DW_CFA_nop amd Row becomes empty. |
244 | // Do not add that to the unwind table. |
245 | if (Row.getRegisterLocations().hasLocations() || |
246 | Row.getCFAValue().getLocation() != UnwindLocation::Unspecified) |
247 | UT.Rows.push_back(x: Row); |
248 | return UT; |
249 | } |
250 | |
251 | // See DWARF standard v3, section 7.23 |
252 | const uint8_t DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0; |
253 | const uint8_t DWARF_CFI_PRIMARY_OPERAND_MASK = 0x3f; |
254 | |
255 | Error CFIProgram::(DWARFDataExtractor Data, uint64_t *Offset, |
256 | uint64_t EndOffset) { |
257 | DataExtractor::Cursor C(*Offset); |
258 | while (C && C.tell() < EndOffset) { |
259 | uint8_t Opcode = Data.getRelocatedValue(C, Size: 1); |
260 | if (!C) |
261 | break; |
262 | |
263 | // Some instructions have a primary opcode encoded in the top bits. |
264 | if (uint8_t Primary = Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK) { |
265 | // If it's a primary opcode, the first operand is encoded in the bottom |
266 | // bits of the opcode itself. |
267 | uint64_t Op1 = Opcode & DWARF_CFI_PRIMARY_OPERAND_MASK; |
268 | switch (Primary) { |
269 | case DW_CFA_advance_loc: |
270 | case DW_CFA_restore: |
271 | addInstruction(Opcode: Primary, Operand1: Op1); |
272 | break; |
273 | case DW_CFA_offset: |
274 | addInstruction(Opcode: Primary, Operand1: Op1, Operand2: Data.getULEB128(C)); |
275 | break; |
276 | default: |
277 | llvm_unreachable("invalid primary CFI opcode" ); |
278 | } |
279 | continue; |
280 | } |
281 | |
282 | // Extended opcode - its value is Opcode itself. |
283 | switch (Opcode) { |
284 | default: |
285 | return createStringError(EC: errc::illegal_byte_sequence, |
286 | Fmt: "invalid extended CFI opcode 0x%" PRIx8, Vals: Opcode); |
287 | case DW_CFA_nop: |
288 | case DW_CFA_remember_state: |
289 | case DW_CFA_restore_state: |
290 | case DW_CFA_GNU_window_save: |
291 | // No operands |
292 | addInstruction(Opcode); |
293 | break; |
294 | case DW_CFA_set_loc: |
295 | // Operands: Address |
296 | addInstruction(Opcode, Operand1: Data.getRelocatedAddress(C)); |
297 | break; |
298 | case DW_CFA_advance_loc1: |
299 | // Operands: 1-byte delta |
300 | addInstruction(Opcode, Operand1: Data.getRelocatedValue(C, Size: 1)); |
301 | break; |
302 | case DW_CFA_advance_loc2: |
303 | // Operands: 2-byte delta |
304 | addInstruction(Opcode, Operand1: Data.getRelocatedValue(C, Size: 2)); |
305 | break; |
306 | case DW_CFA_advance_loc4: |
307 | // Operands: 4-byte delta |
308 | addInstruction(Opcode, Operand1: Data.getRelocatedValue(C, Size: 4)); |
309 | break; |
310 | case DW_CFA_restore_extended: |
311 | case DW_CFA_undefined: |
312 | case DW_CFA_same_value: |
313 | case DW_CFA_def_cfa_register: |
314 | case DW_CFA_def_cfa_offset: |
315 | case DW_CFA_GNU_args_size: |
316 | // Operands: ULEB128 |
317 | addInstruction(Opcode, Operand1: Data.getULEB128(C)); |
318 | break; |
319 | case DW_CFA_def_cfa_offset_sf: |
320 | // Operands: SLEB128 |
321 | addInstruction(Opcode, Operand1: Data.getSLEB128(C)); |
322 | break; |
323 | case DW_CFA_LLVM_def_aspace_cfa: |
324 | case DW_CFA_LLVM_def_aspace_cfa_sf: { |
325 | auto RegNum = Data.getULEB128(C); |
326 | auto CfaOffset = Opcode == DW_CFA_LLVM_def_aspace_cfa |
327 | ? Data.getULEB128(C) |
328 | : Data.getSLEB128(C); |
329 | auto AddressSpace = Data.getULEB128(C); |
330 | addInstruction(Opcode, Operand1: RegNum, Operand2: CfaOffset, Operand3: AddressSpace); |
331 | break; |
332 | } |
333 | case DW_CFA_offset_extended: |
334 | case DW_CFA_register: |
335 | case DW_CFA_def_cfa: |
336 | case DW_CFA_val_offset: { |
337 | // Operands: ULEB128, ULEB128 |
338 | // Note: We can not embed getULEB128 directly into function |
339 | // argument list. getULEB128 changes Offset and order of evaluation |
340 | // for arguments is unspecified. |
341 | uint64_t op1 = Data.getULEB128(C); |
342 | uint64_t op2 = Data.getULEB128(C); |
343 | addInstruction(Opcode, Operand1: op1, Operand2: op2); |
344 | break; |
345 | } |
346 | case DW_CFA_offset_extended_sf: |
347 | case DW_CFA_def_cfa_sf: |
348 | case DW_CFA_val_offset_sf: { |
349 | // Operands: ULEB128, SLEB128 |
350 | // Note: see comment for the previous case |
351 | uint64_t op1 = Data.getULEB128(C); |
352 | uint64_t op2 = (uint64_t)Data.getSLEB128(C); |
353 | addInstruction(Opcode, Operand1: op1, Operand2: op2); |
354 | break; |
355 | } |
356 | case DW_CFA_def_cfa_expression: { |
357 | uint64_t ExprLength = Data.getULEB128(C); |
358 | addInstruction(Opcode, Operand1: 0); |
359 | StringRef Expression = Data.getBytes(C, Length: ExprLength); |
360 | |
361 | DataExtractor (Expression, Data.isLittleEndian(), |
362 | Data.getAddressSize()); |
363 | // Note. We do not pass the DWARF format to DWARFExpression, because |
364 | // DW_OP_call_ref, the only operation which depends on the format, is |
365 | // prohibited in call frame instructions, see sec. 6.4.2 in DWARFv5. |
366 | Instructions.back().Expression = |
367 | DWARFExpression(Extractor, Data.getAddressSize()); |
368 | break; |
369 | } |
370 | case DW_CFA_expression: |
371 | case DW_CFA_val_expression: { |
372 | uint64_t RegNum = Data.getULEB128(C); |
373 | addInstruction(Opcode, Operand1: RegNum, Operand2: 0); |
374 | |
375 | uint64_t BlockLength = Data.getULEB128(C); |
376 | StringRef Expression = Data.getBytes(C, Length: BlockLength); |
377 | DataExtractor (Expression, Data.isLittleEndian(), |
378 | Data.getAddressSize()); |
379 | // Note. We do not pass the DWARF format to DWARFExpression, because |
380 | // DW_OP_call_ref, the only operation which depends on the format, is |
381 | // prohibited in call frame instructions, see sec. 6.4.2 in DWARFv5. |
382 | Instructions.back().Expression = |
383 | DWARFExpression(Extractor, Data.getAddressSize()); |
384 | break; |
385 | } |
386 | } |
387 | } |
388 | |
389 | *Offset = C.tell(); |
390 | return C.takeError(); |
391 | } |
392 | |
393 | StringRef CFIProgram::callFrameString(unsigned Opcode) const { |
394 | return dwarf::CallFrameString(Encoding: Opcode, Arch); |
395 | } |
396 | |
397 | const char *CFIProgram::operandTypeString(CFIProgram::OperandType OT) { |
398 | #define ENUM_TO_CSTR(e) \ |
399 | case e: \ |
400 | return #e; |
401 | switch (OT) { |
402 | ENUM_TO_CSTR(OT_Unset); |
403 | ENUM_TO_CSTR(OT_None); |
404 | ENUM_TO_CSTR(OT_Address); |
405 | ENUM_TO_CSTR(OT_Offset); |
406 | ENUM_TO_CSTR(OT_FactoredCodeOffset); |
407 | ENUM_TO_CSTR(OT_SignedFactDataOffset); |
408 | ENUM_TO_CSTR(OT_UnsignedFactDataOffset); |
409 | ENUM_TO_CSTR(OT_Register); |
410 | ENUM_TO_CSTR(OT_AddressSpace); |
411 | ENUM_TO_CSTR(OT_Expression); |
412 | } |
413 | return "<unknown CFIProgram::OperandType>" ; |
414 | } |
415 | |
416 | llvm::Expected<uint64_t> |
417 | CFIProgram::Instruction::getOperandAsUnsigned(const CFIProgram &CFIP, |
418 | uint32_t OperandIdx) const { |
419 | if (OperandIdx >= MaxOperands) |
420 | return createStringError(EC: errc::invalid_argument, |
421 | Fmt: "operand index %" PRIu32 " is not valid" , |
422 | Vals: OperandIdx); |
423 | OperandType Type = CFIP.getOperandTypes()[Opcode][OperandIdx]; |
424 | uint64_t Operand = Ops[OperandIdx]; |
425 | switch (Type) { |
426 | case OT_Unset: |
427 | case OT_None: |
428 | case OT_Expression: |
429 | return createStringError(EC: errc::invalid_argument, |
430 | Fmt: "op[%" PRIu32 "] has type %s which has no value" , |
431 | Vals: OperandIdx, Vals: CFIProgram::operandTypeString(OT: Type)); |
432 | |
433 | case OT_Offset: |
434 | case OT_SignedFactDataOffset: |
435 | case OT_UnsignedFactDataOffset: |
436 | return createStringError( |
437 | EC: errc::invalid_argument, |
438 | Fmt: "op[%" PRIu32 "] has OperandType OT_Offset which produces a signed " |
439 | "result, call getOperandAsSigned instead" , |
440 | Vals: OperandIdx); |
441 | |
442 | case OT_Address: |
443 | case OT_Register: |
444 | case OT_AddressSpace: |
445 | return Operand; |
446 | |
447 | case OT_FactoredCodeOffset: { |
448 | const uint64_t CodeAlignmentFactor = CFIP.codeAlign(); |
449 | if (CodeAlignmentFactor == 0) |
450 | return createStringError( |
451 | EC: errc::invalid_argument, |
452 | Fmt: "op[%" PRIu32 "] has type OT_FactoredCodeOffset but code alignment " |
453 | "is zero" , |
454 | Vals: OperandIdx); |
455 | return Operand * CodeAlignmentFactor; |
456 | } |
457 | } |
458 | llvm_unreachable("invalid operand type" ); |
459 | } |
460 | |
461 | llvm::Expected<int64_t> |
462 | CFIProgram::Instruction::getOperandAsSigned(const CFIProgram &CFIP, |
463 | uint32_t OperandIdx) const { |
464 | if (OperandIdx >= MaxOperands) |
465 | return createStringError(EC: errc::invalid_argument, |
466 | Fmt: "operand index %" PRIu32 " is not valid" , |
467 | Vals: OperandIdx); |
468 | OperandType Type = CFIP.getOperandTypes()[Opcode][OperandIdx]; |
469 | uint64_t Operand = Ops[OperandIdx]; |
470 | switch (Type) { |
471 | case OT_Unset: |
472 | case OT_None: |
473 | case OT_Expression: |
474 | return createStringError(EC: errc::invalid_argument, |
475 | Fmt: "op[%" PRIu32 "] has type %s which has no value" , |
476 | Vals: OperandIdx, Vals: CFIProgram::operandTypeString(OT: Type)); |
477 | |
478 | case OT_Address: |
479 | case OT_Register: |
480 | case OT_AddressSpace: |
481 | return createStringError( |
482 | EC: errc::invalid_argument, |
483 | Fmt: "op[%" PRIu32 "] has OperandType %s which produces an unsigned result, " |
484 | "call getOperandAsUnsigned instead" , |
485 | Vals: OperandIdx, Vals: CFIProgram::operandTypeString(OT: Type)); |
486 | |
487 | case OT_Offset: |
488 | return (int64_t)Operand; |
489 | |
490 | case OT_FactoredCodeOffset: |
491 | case OT_SignedFactDataOffset: { |
492 | const int64_t DataAlignmentFactor = CFIP.dataAlign(); |
493 | if (DataAlignmentFactor == 0) |
494 | return createStringError(EC: errc::invalid_argument, |
495 | Fmt: "op[%" PRIu32 "] has type %s but data " |
496 | "alignment is zero" , |
497 | Vals: OperandIdx, Vals: CFIProgram::operandTypeString(OT: Type)); |
498 | return int64_t(Operand) * DataAlignmentFactor; |
499 | } |
500 | |
501 | case OT_UnsignedFactDataOffset: { |
502 | const int64_t DataAlignmentFactor = CFIP.dataAlign(); |
503 | if (DataAlignmentFactor == 0) |
504 | return createStringError(EC: errc::invalid_argument, |
505 | Fmt: "op[%" PRIu32 |
506 | "] has type OT_UnsignedFactDataOffset but data " |
507 | "alignment is zero" , |
508 | Vals: OperandIdx); |
509 | return Operand * DataAlignmentFactor; |
510 | } |
511 | } |
512 | llvm_unreachable("invalid operand type" ); |
513 | } |
514 | |
515 | Error UnwindTable::parseRows(const CFIProgram &CFIP, UnwindRow &Row, |
516 | const RegisterLocations *InitialLocs) { |
517 | // State consists of CFA value and register locations. |
518 | std::vector<std::pair<UnwindLocation, RegisterLocations>> States; |
519 | for (const CFIProgram::Instruction &Inst : CFIP) { |
520 | switch (Inst.Opcode) { |
521 | case dwarf::DW_CFA_set_loc: { |
522 | // The DW_CFA_set_loc instruction takes a single operand that |
523 | // represents a target address. The required action is to create a new |
524 | // table row using the specified address as the location. All other |
525 | // values in the new row are initially identical to the current row. |
526 | // The new location value is always greater than the current one. If |
527 | // the segment_size field of this FDE's CIE is non- zero, the initial |
528 | // location is preceded by a segment selector of the given length |
529 | llvm::Expected<uint64_t> NewAddress = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 0); |
530 | if (!NewAddress) |
531 | return NewAddress.takeError(); |
532 | if (*NewAddress <= Row.getAddress()) |
533 | return createStringError( |
534 | EC: errc::invalid_argument, |
535 | Fmt: "%s with adrress 0x%" PRIx64 " which must be greater than the " |
536 | "current row address 0x%" PRIx64, |
537 | Vals: CFIP.callFrameString(Opcode: Inst.Opcode).str().c_str(), Vals: *NewAddress, |
538 | Vals: Row.getAddress()); |
539 | Rows.push_back(x: Row); |
540 | Row.setAddress(*NewAddress); |
541 | break; |
542 | } |
543 | |
544 | case dwarf::DW_CFA_advance_loc: |
545 | case dwarf::DW_CFA_advance_loc1: |
546 | case dwarf::DW_CFA_advance_loc2: |
547 | case dwarf::DW_CFA_advance_loc4: { |
548 | // The DW_CFA_advance instruction takes a single operand that |
549 | // represents a constant delta. The required action is to create a new |
550 | // table row with a location value that is computed by taking the |
551 | // current entry’s location value and adding the value of delta * |
552 | // code_alignment_factor. All other values in the new row are initially |
553 | // identical to the current row. |
554 | Rows.push_back(x: Row); |
555 | llvm::Expected<uint64_t> Offset = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 0); |
556 | if (!Offset) |
557 | return Offset.takeError(); |
558 | Row.slideAddress(Offset: *Offset); |
559 | break; |
560 | } |
561 | |
562 | case dwarf::DW_CFA_restore: |
563 | case dwarf::DW_CFA_restore_extended: { |
564 | // The DW_CFA_restore instruction takes a single operand (encoded with |
565 | // the opcode) that represents a register number. The required action |
566 | // is to change the rule for the indicated register to the rule |
567 | // assigned it by the initial_instructions in the CIE. |
568 | if (InitialLocs == nullptr) |
569 | return createStringError( |
570 | EC: errc::invalid_argument, Fmt: "%s encountered while parsing a CIE" , |
571 | Vals: CFIP.callFrameString(Opcode: Inst.Opcode).str().c_str()); |
572 | llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 0); |
573 | if (!RegNum) |
574 | return RegNum.takeError(); |
575 | if (std::optional<UnwindLocation> O = |
576 | InitialLocs->getRegisterLocation(RegNum: *RegNum)) |
577 | Row.getRegisterLocations().setRegisterLocation(RegNum: *RegNum, Location: *O); |
578 | else |
579 | Row.getRegisterLocations().removeRegisterLocation(RegNum: *RegNum); |
580 | break; |
581 | } |
582 | |
583 | case dwarf::DW_CFA_offset: |
584 | case dwarf::DW_CFA_offset_extended: |
585 | case dwarf::DW_CFA_offset_extended_sf: { |
586 | llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 0); |
587 | if (!RegNum) |
588 | return RegNum.takeError(); |
589 | llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, OperandIdx: 1); |
590 | if (!Offset) |
591 | return Offset.takeError(); |
592 | Row.getRegisterLocations().setRegisterLocation( |
593 | RegNum: *RegNum, Location: UnwindLocation::createAtCFAPlusOffset(Offset: *Offset)); |
594 | break; |
595 | } |
596 | |
597 | case dwarf::DW_CFA_nop: |
598 | break; |
599 | |
600 | case dwarf::DW_CFA_remember_state: |
601 | States.push_back( |
602 | x: std::make_pair(x&: Row.getCFAValue(), y&: Row.getRegisterLocations())); |
603 | break; |
604 | |
605 | case dwarf::DW_CFA_restore_state: |
606 | if (States.empty()) |
607 | return createStringError(EC: errc::invalid_argument, |
608 | S: "DW_CFA_restore_state without a matching " |
609 | "previous DW_CFA_remember_state" ); |
610 | Row.getCFAValue() = States.back().first; |
611 | Row.getRegisterLocations() = States.back().second; |
612 | States.pop_back(); |
613 | break; |
614 | |
615 | case dwarf::DW_CFA_GNU_window_save: |
616 | switch (CFIP.triple()) { |
617 | case Triple::aarch64: |
618 | case Triple::aarch64_be: |
619 | case Triple::aarch64_32: { |
620 | // DW_CFA_GNU_window_save is used for different things on different |
621 | // architectures. For aarch64 it is known as |
622 | // DW_CFA_AARCH64_negate_ra_state. The action is to toggle the |
623 | // value of the return address state between 1 and 0. If there is |
624 | // no rule for the AARCH64_DWARF_PAUTH_RA_STATE register, then it |
625 | // should be initially set to 1. |
626 | constexpr uint32_t AArch64DWARFPAuthRaState = 34; |
627 | auto LRLoc = Row.getRegisterLocations().getRegisterLocation( |
628 | RegNum: AArch64DWARFPAuthRaState); |
629 | if (LRLoc) { |
630 | if (LRLoc->getLocation() == UnwindLocation::Constant) { |
631 | // Toggle the constant value from 0 to 1 or 1 to 0. |
632 | LRLoc->setConstant(LRLoc->getConstant() ^ 1); |
633 | Row.getRegisterLocations().setRegisterLocation( |
634 | RegNum: AArch64DWARFPAuthRaState, Location: *LRLoc); |
635 | } else { |
636 | return createStringError( |
637 | EC: errc::invalid_argument, |
638 | Fmt: "%s encountered when existing rule for this register is not " |
639 | "a constant" , |
640 | Vals: CFIP.callFrameString(Opcode: Inst.Opcode).str().c_str()); |
641 | } |
642 | } else { |
643 | Row.getRegisterLocations().setRegisterLocation( |
644 | RegNum: AArch64DWARFPAuthRaState, Location: UnwindLocation::createIsConstant(Value: 1)); |
645 | } |
646 | break; |
647 | } |
648 | |
649 | case Triple::sparc: |
650 | case Triple::sparcv9: |
651 | case Triple::sparcel: |
652 | for (uint32_t RegNum = 16; RegNum < 32; ++RegNum) { |
653 | Row.getRegisterLocations().setRegisterLocation( |
654 | RegNum, Location: UnwindLocation::createAtCFAPlusOffset(Offset: (RegNum - 16) * 8)); |
655 | } |
656 | break; |
657 | |
658 | default: { |
659 | return createStringError( |
660 | EC: errc::not_supported, |
661 | Fmt: "DW_CFA opcode %#x is not supported for architecture %s" , |
662 | Vals: Inst.Opcode, Vals: Triple::getArchTypeName(Kind: CFIP.triple()).str().c_str()); |
663 | |
664 | break; |
665 | } |
666 | } |
667 | break; |
668 | |
669 | case dwarf::DW_CFA_undefined: { |
670 | llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 0); |
671 | if (!RegNum) |
672 | return RegNum.takeError(); |
673 | Row.getRegisterLocations().setRegisterLocation( |
674 | RegNum: *RegNum, Location: UnwindLocation::createUndefined()); |
675 | break; |
676 | } |
677 | |
678 | case dwarf::DW_CFA_same_value: { |
679 | llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 0); |
680 | if (!RegNum) |
681 | return RegNum.takeError(); |
682 | Row.getRegisterLocations().setRegisterLocation( |
683 | RegNum: *RegNum, Location: UnwindLocation::createSame()); |
684 | break; |
685 | } |
686 | |
687 | case dwarf::DW_CFA_GNU_args_size: |
688 | break; |
689 | |
690 | case dwarf::DW_CFA_register: { |
691 | llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 0); |
692 | if (!RegNum) |
693 | return RegNum.takeError(); |
694 | llvm::Expected<uint64_t> NewRegNum = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 1); |
695 | if (!NewRegNum) |
696 | return NewRegNum.takeError(); |
697 | Row.getRegisterLocations().setRegisterLocation( |
698 | RegNum: *RegNum, Location: UnwindLocation::createIsRegisterPlusOffset(RegNum: *NewRegNum, Offset: 0)); |
699 | break; |
700 | } |
701 | |
702 | case dwarf::DW_CFA_val_offset: |
703 | case dwarf::DW_CFA_val_offset_sf: { |
704 | llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 0); |
705 | if (!RegNum) |
706 | return RegNum.takeError(); |
707 | llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, OperandIdx: 1); |
708 | if (!Offset) |
709 | return Offset.takeError(); |
710 | Row.getRegisterLocations().setRegisterLocation( |
711 | RegNum: *RegNum, Location: UnwindLocation::createIsCFAPlusOffset(Offset: *Offset)); |
712 | break; |
713 | } |
714 | |
715 | case dwarf::DW_CFA_expression: { |
716 | llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 0); |
717 | if (!RegNum) |
718 | return RegNum.takeError(); |
719 | Row.getRegisterLocations().setRegisterLocation( |
720 | RegNum: *RegNum, Location: UnwindLocation::createAtDWARFExpression(Expr: *Inst.Expression)); |
721 | break; |
722 | } |
723 | |
724 | case dwarf::DW_CFA_val_expression: { |
725 | llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 0); |
726 | if (!RegNum) |
727 | return RegNum.takeError(); |
728 | Row.getRegisterLocations().setRegisterLocation( |
729 | RegNum: *RegNum, Location: UnwindLocation::createIsDWARFExpression(Expr: *Inst.Expression)); |
730 | break; |
731 | } |
732 | |
733 | case dwarf::DW_CFA_def_cfa_register: { |
734 | llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 0); |
735 | if (!RegNum) |
736 | return RegNum.takeError(); |
737 | if (Row.getCFAValue().getLocation() != UnwindLocation::RegPlusOffset) |
738 | Row.getCFAValue() = |
739 | UnwindLocation::createIsRegisterPlusOffset(RegNum: *RegNum, Offset: 0); |
740 | else |
741 | Row.getCFAValue().setRegister(*RegNum); |
742 | break; |
743 | } |
744 | |
745 | case dwarf::DW_CFA_def_cfa_offset: |
746 | case dwarf::DW_CFA_def_cfa_offset_sf: { |
747 | llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, OperandIdx: 0); |
748 | if (!Offset) |
749 | return Offset.takeError(); |
750 | if (Row.getCFAValue().getLocation() != UnwindLocation::RegPlusOffset) { |
751 | return createStringError( |
752 | EC: errc::invalid_argument, |
753 | Fmt: "%s found when CFA rule was not RegPlusOffset" , |
754 | Vals: CFIP.callFrameString(Opcode: Inst.Opcode).str().c_str()); |
755 | } |
756 | Row.getCFAValue().setOffset(*Offset); |
757 | break; |
758 | } |
759 | |
760 | case dwarf::DW_CFA_def_cfa: |
761 | case dwarf::DW_CFA_def_cfa_sf: { |
762 | llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 0); |
763 | if (!RegNum) |
764 | return RegNum.takeError(); |
765 | llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, OperandIdx: 1); |
766 | if (!Offset) |
767 | return Offset.takeError(); |
768 | Row.getCFAValue() = |
769 | UnwindLocation::createIsRegisterPlusOffset(RegNum: *RegNum, Offset: *Offset); |
770 | break; |
771 | } |
772 | |
773 | case dwarf::DW_CFA_LLVM_def_aspace_cfa: |
774 | case dwarf::DW_CFA_LLVM_def_aspace_cfa_sf: { |
775 | llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, OperandIdx: 0); |
776 | if (!RegNum) |
777 | return RegNum.takeError(); |
778 | llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, OperandIdx: 1); |
779 | if (!Offset) |
780 | return Offset.takeError(); |
781 | llvm::Expected<uint32_t> CFAAddrSpace = |
782 | Inst.getOperandAsUnsigned(CFIP, OperandIdx: 2); |
783 | if (!CFAAddrSpace) |
784 | return CFAAddrSpace.takeError(); |
785 | Row.getCFAValue() = UnwindLocation::createIsRegisterPlusOffset( |
786 | RegNum: *RegNum, Offset: *Offset, AddrSpace: *CFAAddrSpace); |
787 | break; |
788 | } |
789 | |
790 | case dwarf::DW_CFA_def_cfa_expression: |
791 | Row.getCFAValue() = |
792 | UnwindLocation::createIsDWARFExpression(Expr: *Inst.Expression); |
793 | break; |
794 | } |
795 | } |
796 | return Error::success(); |
797 | } |
798 | |
799 | ArrayRef<CFIProgram::OperandType[CFIProgram::MaxOperands]> |
800 | CFIProgram::getOperandTypes() { |
801 | static OperandType OpTypes[DW_CFA_restore + 1][MaxOperands]; |
802 | static bool Initialized = false; |
803 | if (Initialized) { |
804 | return ArrayRef<OperandType[MaxOperands]>(&OpTypes[0], DW_CFA_restore + 1); |
805 | } |
806 | Initialized = true; |
807 | |
808 | #define DECLARE_OP3(OP, OPTYPE0, OPTYPE1, OPTYPE2) \ |
809 | do { \ |
810 | OpTypes[OP][0] = OPTYPE0; \ |
811 | OpTypes[OP][1] = OPTYPE1; \ |
812 | OpTypes[OP][2] = OPTYPE2; \ |
813 | } while (false) |
814 | #define DECLARE_OP2(OP, OPTYPE0, OPTYPE1) \ |
815 | DECLARE_OP3(OP, OPTYPE0, OPTYPE1, OT_None) |
816 | #define DECLARE_OP1(OP, OPTYPE0) DECLARE_OP2(OP, OPTYPE0, OT_None) |
817 | #define DECLARE_OP0(OP) DECLARE_OP1(OP, OT_None) |
818 | |
819 | DECLARE_OP1(DW_CFA_set_loc, OT_Address); |
820 | DECLARE_OP1(DW_CFA_advance_loc, OT_FactoredCodeOffset); |
821 | DECLARE_OP1(DW_CFA_advance_loc1, OT_FactoredCodeOffset); |
822 | DECLARE_OP1(DW_CFA_advance_loc2, OT_FactoredCodeOffset); |
823 | DECLARE_OP1(DW_CFA_advance_loc4, OT_FactoredCodeOffset); |
824 | DECLARE_OP1(DW_CFA_MIPS_advance_loc8, OT_FactoredCodeOffset); |
825 | DECLARE_OP2(DW_CFA_def_cfa, OT_Register, OT_Offset); |
826 | DECLARE_OP2(DW_CFA_def_cfa_sf, OT_Register, OT_SignedFactDataOffset); |
827 | DECLARE_OP1(DW_CFA_def_cfa_register, OT_Register); |
828 | DECLARE_OP3(DW_CFA_LLVM_def_aspace_cfa, OT_Register, OT_Offset, |
829 | OT_AddressSpace); |
830 | DECLARE_OP3(DW_CFA_LLVM_def_aspace_cfa_sf, OT_Register, |
831 | OT_SignedFactDataOffset, OT_AddressSpace); |
832 | DECLARE_OP1(DW_CFA_def_cfa_offset, OT_Offset); |
833 | DECLARE_OP1(DW_CFA_def_cfa_offset_sf, OT_SignedFactDataOffset); |
834 | DECLARE_OP1(DW_CFA_def_cfa_expression, OT_Expression); |
835 | DECLARE_OP1(DW_CFA_undefined, OT_Register); |
836 | DECLARE_OP1(DW_CFA_same_value, OT_Register); |
837 | DECLARE_OP2(DW_CFA_offset, OT_Register, OT_UnsignedFactDataOffset); |
838 | DECLARE_OP2(DW_CFA_offset_extended, OT_Register, OT_UnsignedFactDataOffset); |
839 | DECLARE_OP2(DW_CFA_offset_extended_sf, OT_Register, OT_SignedFactDataOffset); |
840 | DECLARE_OP2(DW_CFA_val_offset, OT_Register, OT_UnsignedFactDataOffset); |
841 | DECLARE_OP2(DW_CFA_val_offset_sf, OT_Register, OT_SignedFactDataOffset); |
842 | DECLARE_OP2(DW_CFA_register, OT_Register, OT_Register); |
843 | DECLARE_OP2(DW_CFA_expression, OT_Register, OT_Expression); |
844 | DECLARE_OP2(DW_CFA_val_expression, OT_Register, OT_Expression); |
845 | DECLARE_OP1(DW_CFA_restore, OT_Register); |
846 | DECLARE_OP1(DW_CFA_restore_extended, OT_Register); |
847 | DECLARE_OP0(DW_CFA_remember_state); |
848 | DECLARE_OP0(DW_CFA_restore_state); |
849 | DECLARE_OP0(DW_CFA_GNU_window_save); |
850 | DECLARE_OP1(DW_CFA_GNU_args_size, OT_Offset); |
851 | DECLARE_OP0(DW_CFA_nop); |
852 | |
853 | #undef DECLARE_OP0 |
854 | #undef DECLARE_OP1 |
855 | #undef DECLARE_OP2 |
856 | |
857 | return ArrayRef<OperandType[MaxOperands]>(&OpTypes[0], DW_CFA_restore + 1); |
858 | } |
859 | |
860 | /// Print \p Opcode's operand number \p OperandIdx which has value \p Operand. |
861 | void CFIProgram::printOperand(raw_ostream &OS, DIDumpOptions DumpOpts, |
862 | const Instruction &Instr, unsigned OperandIdx, |
863 | uint64_t Operand, |
864 | std::optional<uint64_t> &Address) const { |
865 | assert(OperandIdx < MaxOperands); |
866 | uint8_t Opcode = Instr.Opcode; |
867 | OperandType Type = getOperandTypes()[Opcode][OperandIdx]; |
868 | |
869 | switch (Type) { |
870 | case OT_Unset: { |
871 | OS << " Unsupported " << (OperandIdx ? "second" : "first" ) << " operand to" ; |
872 | auto OpcodeName = callFrameString(Opcode); |
873 | if (!OpcodeName.empty()) |
874 | OS << " " << OpcodeName; |
875 | else |
876 | OS << format(Fmt: " Opcode %x" , Vals: Opcode); |
877 | break; |
878 | } |
879 | case OT_None: |
880 | break; |
881 | case OT_Address: |
882 | OS << format(Fmt: " %" PRIx64, Vals: Operand); |
883 | Address = Operand; |
884 | break; |
885 | case OT_Offset: |
886 | // The offsets are all encoded in a unsigned form, but in practice |
887 | // consumers use them signed. It's most certainly legacy due to |
888 | // the lack of signed variants in the first Dwarf standards. |
889 | OS << format(Fmt: " %+" PRId64, Vals: int64_t(Operand)); |
890 | break; |
891 | case OT_FactoredCodeOffset: // Always Unsigned |
892 | if (CodeAlignmentFactor) |
893 | OS << format(Fmt: " %" PRId64, Vals: Operand * CodeAlignmentFactor); |
894 | else |
895 | OS << format(Fmt: " %" PRId64 "*code_alignment_factor" , Vals: Operand); |
896 | if (Address && CodeAlignmentFactor) { |
897 | *Address += Operand * CodeAlignmentFactor; |
898 | OS << format(Fmt: " to 0x%" PRIx64, Vals: *Address); |
899 | } |
900 | break; |
901 | case OT_SignedFactDataOffset: |
902 | if (DataAlignmentFactor) |
903 | OS << format(Fmt: " %" PRId64, Vals: int64_t(Operand) * DataAlignmentFactor); |
904 | else |
905 | OS << format(Fmt: " %" PRId64 "*data_alignment_factor" , Vals: int64_t(Operand)); |
906 | break; |
907 | case OT_UnsignedFactDataOffset: |
908 | if (DataAlignmentFactor) |
909 | OS << format(Fmt: " %" PRId64, Vals: Operand * DataAlignmentFactor); |
910 | else |
911 | OS << format(Fmt: " %" PRId64 "*data_alignment_factor" , Vals: Operand); |
912 | break; |
913 | case OT_Register: |
914 | OS << ' '; |
915 | printRegister(OS, DumpOpts, RegNum: Operand); |
916 | break; |
917 | case OT_AddressSpace: |
918 | OS << format(Fmt: " in addrspace%" PRId64, Vals: Operand); |
919 | break; |
920 | case OT_Expression: |
921 | assert(Instr.Expression && "missing DWARFExpression object" ); |
922 | OS << " " ; |
923 | Instr.Expression->print(OS, DumpOpts, U: nullptr); |
924 | break; |
925 | } |
926 | } |
927 | |
928 | void CFIProgram::dump(raw_ostream &OS, DIDumpOptions DumpOpts, |
929 | unsigned IndentLevel, |
930 | std::optional<uint64_t> Address) const { |
931 | for (const auto &Instr : Instructions) { |
932 | uint8_t Opcode = Instr.Opcode; |
933 | OS.indent(NumSpaces: 2 * IndentLevel); |
934 | OS << callFrameString(Opcode) << ":" ; |
935 | for (unsigned i = 0; i < Instr.Ops.size(); ++i) |
936 | printOperand(OS, DumpOpts, Instr, OperandIdx: i, Operand: Instr.Ops[i], Address); |
937 | OS << '\n'; |
938 | } |
939 | } |
940 | |
941 | // Returns the CIE identifier to be used by the requested format. |
942 | // CIE ids for .debug_frame sections are defined in Section 7.24 of DWARFv5. |
943 | // For CIE ID in .eh_frame sections see |
944 | // https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html |
945 | constexpr uint64_t getCIEId(bool IsDWARF64, bool IsEH) { |
946 | if (IsEH) |
947 | return 0; |
948 | if (IsDWARF64) |
949 | return DW64_CIE_ID; |
950 | return DW_CIE_ID; |
951 | } |
952 | |
953 | void CIE::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const { |
954 | // A CIE with a zero length is a terminator entry in the .eh_frame section. |
955 | if (DumpOpts.IsEH && Length == 0) { |
956 | OS << format(Fmt: "%08" PRIx64, Vals: Offset) << " ZERO terminator\n" ; |
957 | return; |
958 | } |
959 | |
960 | OS << format(Fmt: "%08" PRIx64, Vals: Offset) |
961 | << format(Fmt: " %0*" PRIx64, Vals: IsDWARF64 ? 16 : 8, Vals: Length) |
962 | << format(Fmt: " %0*" PRIx64, Vals: IsDWARF64 && !DumpOpts.IsEH ? 16 : 8, |
963 | Vals: getCIEId(IsDWARF64, IsEH: DumpOpts.IsEH)) |
964 | << " CIE\n" |
965 | << " Format: " << FormatString(IsDWARF64) << "\n" ; |
966 | if (DumpOpts.IsEH && Version != 1) |
967 | OS << "WARNING: unsupported CIE version\n" ; |
968 | OS << format(Fmt: " Version: %d\n" , Vals: Version) |
969 | << " Augmentation: \"" << Augmentation << "\"\n" ; |
970 | if (Version >= 4) { |
971 | OS << format(Fmt: " Address size: %u\n" , Vals: (uint32_t)AddressSize); |
972 | OS << format(Fmt: " Segment desc size: %u\n" , |
973 | Vals: (uint32_t)SegmentDescriptorSize); |
974 | } |
975 | OS << format(Fmt: " Code alignment factor: %u\n" , Vals: (uint32_t)CodeAlignmentFactor); |
976 | OS << format(Fmt: " Data alignment factor: %d\n" , Vals: (int32_t)DataAlignmentFactor); |
977 | OS << format(Fmt: " Return address column: %d\n" , Vals: (int32_t)ReturnAddressRegister); |
978 | if (Personality) |
979 | OS << format(Fmt: " Personality Address: %016" PRIx64 "\n" , Vals: *Personality); |
980 | if (!AugmentationData.empty()) { |
981 | OS << " Augmentation data: " ; |
982 | for (uint8_t Byte : AugmentationData) |
983 | OS << ' ' << hexdigit(X: Byte >> 4) << hexdigit(X: Byte & 0xf); |
984 | OS << "\n" ; |
985 | } |
986 | OS << "\n" ; |
987 | CFIs.dump(OS, DumpOpts, /*IndentLevel=*/1, /*InitialLocation=*/Address: {}); |
988 | OS << "\n" ; |
989 | |
990 | if (Expected<UnwindTable> RowsOrErr = UnwindTable::create(Cie: this)) |
991 | RowsOrErr->dump(OS, DumpOpts, IndentLevel: 1); |
992 | else { |
993 | DumpOpts.RecoverableErrorHandler(joinErrors( |
994 | E1: createStringError(EC: errc::invalid_argument, |
995 | S: "decoding the CIE opcodes into rows failed" ), |
996 | E2: RowsOrErr.takeError())); |
997 | } |
998 | OS << "\n" ; |
999 | } |
1000 | |
1001 | void FDE::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const { |
1002 | OS << format(Fmt: "%08" PRIx64, Vals: Offset) |
1003 | << format(Fmt: " %0*" PRIx64, Vals: IsDWARF64 ? 16 : 8, Vals: Length) |
1004 | << format(Fmt: " %0*" PRIx64, Vals: IsDWARF64 && !DumpOpts.IsEH ? 16 : 8, Vals: CIEPointer) |
1005 | << " FDE cie=" ; |
1006 | if (LinkedCIE) |
1007 | OS << format(Fmt: "%08" PRIx64, Vals: LinkedCIE->getOffset()); |
1008 | else |
1009 | OS << "<invalid offset>" ; |
1010 | OS << format(Fmt: " pc=%08" PRIx64 "...%08" PRIx64 "\n" , Vals: InitialLocation, |
1011 | Vals: InitialLocation + AddressRange); |
1012 | OS << " Format: " << FormatString(IsDWARF64) << "\n" ; |
1013 | if (LSDAAddress) |
1014 | OS << format(Fmt: " LSDA Address: %016" PRIx64 "\n" , Vals: *LSDAAddress); |
1015 | CFIs.dump(OS, DumpOpts, /*IndentLevel=*/1, Address: InitialLocation); |
1016 | OS << "\n" ; |
1017 | |
1018 | if (Expected<UnwindTable> RowsOrErr = UnwindTable::create(Fde: this)) |
1019 | RowsOrErr->dump(OS, DumpOpts, IndentLevel: 1); |
1020 | else { |
1021 | DumpOpts.RecoverableErrorHandler(joinErrors( |
1022 | E1: createStringError(EC: errc::invalid_argument, |
1023 | S: "decoding the FDE opcodes into rows failed" ), |
1024 | E2: RowsOrErr.takeError())); |
1025 | } |
1026 | OS << "\n" ; |
1027 | } |
1028 | |
1029 | DWARFDebugFrame::DWARFDebugFrame(Triple::ArchType Arch, |
1030 | bool IsEH, uint64_t EHFrameAddress) |
1031 | : Arch(Arch), IsEH(IsEH), EHFrameAddress(EHFrameAddress) {} |
1032 | |
1033 | DWARFDebugFrame::~DWARFDebugFrame() = default; |
1034 | |
1035 | static void LLVM_ATTRIBUTE_UNUSED (DataExtractor Data, |
1036 | uint64_t Offset, int Length) { |
1037 | errs() << "DUMP: " ; |
1038 | for (int i = 0; i < Length; ++i) { |
1039 | uint8_t c = Data.getU8(offset_ptr: &Offset); |
1040 | errs().write_hex(N: c); errs() << " " ; |
1041 | } |
1042 | errs() << "\n" ; |
1043 | } |
1044 | |
1045 | Error DWARFDebugFrame::(DWARFDataExtractor Data) { |
1046 | uint64_t Offset = 0; |
1047 | DenseMap<uint64_t, CIE *> CIEs; |
1048 | |
1049 | while (Data.isValidOffset(offset: Offset)) { |
1050 | uint64_t StartOffset = Offset; |
1051 | |
1052 | uint64_t Length; |
1053 | DwarfFormat Format; |
1054 | std::tie(args&: Length, args&: Format) = Data.getInitialLength(Off: &Offset); |
1055 | bool IsDWARF64 = Format == DWARF64; |
1056 | |
1057 | // If the Length is 0, then this CIE is a terminator. We add it because some |
1058 | // dumper tools might need it to print something special for such entries |
1059 | // (e.g. llvm-objdump --dwarf=frames prints "ZERO terminator"). |
1060 | if (Length == 0) { |
1061 | auto Cie = std::make_unique<CIE>( |
1062 | args&: IsDWARF64, args&: StartOffset, args: 0, args: 0, args: SmallString<8>(), args: 0, args: 0, args: 0, args: 0, args: 0, |
1063 | args: SmallString<8>(), args: 0, args: 0, args: std::nullopt, args: std::nullopt, args: Arch); |
1064 | CIEs[StartOffset] = Cie.get(); |
1065 | Entries.push_back(x: std::move(Cie)); |
1066 | break; |
1067 | } |
1068 | |
1069 | // At this point, Offset points to the next field after Length. |
1070 | // Length is the structure size excluding itself. Compute an offset one |
1071 | // past the end of the structure (needed to know how many instructions to |
1072 | // read). |
1073 | uint64_t StartStructureOffset = Offset; |
1074 | uint64_t EndStructureOffset = Offset + Length; |
1075 | |
1076 | // The Id field's size depends on the DWARF format |
1077 | Error Err = Error::success(); |
1078 | uint64_t Id = Data.getRelocatedValue(Size: (IsDWARF64 && !IsEH) ? 8 : 4, Off: &Offset, |
1079 | /*SectionIndex=*/nullptr, Err: &Err); |
1080 | if (Err) |
1081 | return Err; |
1082 | |
1083 | if (Id == getCIEId(IsDWARF64, IsEH)) { |
1084 | uint8_t Version = Data.getU8(offset_ptr: &Offset); |
1085 | const char *Augmentation = Data.getCStr(OffsetPtr: &Offset); |
1086 | StringRef AugmentationString(Augmentation ? Augmentation : "" ); |
1087 | uint8_t AddressSize = Version < 4 ? Data.getAddressSize() : |
1088 | Data.getU8(offset_ptr: &Offset); |
1089 | Data.setAddressSize(AddressSize); |
1090 | uint8_t SegmentDescriptorSize = Version < 4 ? 0 : Data.getU8(offset_ptr: &Offset); |
1091 | uint64_t CodeAlignmentFactor = Data.getULEB128(offset_ptr: &Offset); |
1092 | int64_t DataAlignmentFactor = Data.getSLEB128(OffsetPtr: &Offset); |
1093 | uint64_t ReturnAddressRegister = |
1094 | Version == 1 ? Data.getU8(offset_ptr: &Offset) : Data.getULEB128(offset_ptr: &Offset); |
1095 | |
1096 | // Parse the augmentation data for EH CIEs |
1097 | StringRef AugmentationData("" ); |
1098 | uint32_t FDEPointerEncoding = DW_EH_PE_absptr; |
1099 | uint32_t LSDAPointerEncoding = DW_EH_PE_omit; |
1100 | std::optional<uint64_t> Personality; |
1101 | std::optional<uint32_t> PersonalityEncoding; |
1102 | if (IsEH) { |
1103 | std::optional<uint64_t> AugmentationLength; |
1104 | uint64_t StartAugmentationOffset; |
1105 | uint64_t EndAugmentationOffset; |
1106 | |
1107 | // Walk the augmentation string to get all the augmentation data. |
1108 | for (unsigned i = 0, e = AugmentationString.size(); i != e; ++i) { |
1109 | switch (AugmentationString[i]) { |
1110 | default: |
1111 | return createStringError( |
1112 | EC: errc::invalid_argument, |
1113 | Fmt: "unknown augmentation character %c in entry at 0x%" PRIx64, |
1114 | Vals: AugmentationString[i], Vals: StartOffset); |
1115 | case 'L': |
1116 | LSDAPointerEncoding = Data.getU8(offset_ptr: &Offset); |
1117 | break; |
1118 | case 'P': { |
1119 | if (Personality) |
1120 | return createStringError( |
1121 | EC: errc::invalid_argument, |
1122 | Fmt: "duplicate personality in entry at 0x%" PRIx64, Vals: StartOffset); |
1123 | PersonalityEncoding = Data.getU8(offset_ptr: &Offset); |
1124 | Personality = Data.getEncodedPointer( |
1125 | Offset: &Offset, Encoding: *PersonalityEncoding, |
1126 | AbsPosOffset: EHFrameAddress ? EHFrameAddress + Offset : 0); |
1127 | break; |
1128 | } |
1129 | case 'R': |
1130 | FDEPointerEncoding = Data.getU8(offset_ptr: &Offset); |
1131 | break; |
1132 | case 'S': |
1133 | // Current frame is a signal trampoline. |
1134 | break; |
1135 | case 'z': |
1136 | if (i) |
1137 | return createStringError( |
1138 | EC: errc::invalid_argument, |
1139 | Fmt: "'z' must be the first character at 0x%" PRIx64, Vals: StartOffset); |
1140 | // Parse the augmentation length first. We only parse it if |
1141 | // the string contains a 'z'. |
1142 | AugmentationLength = Data.getULEB128(offset_ptr: &Offset); |
1143 | StartAugmentationOffset = Offset; |
1144 | EndAugmentationOffset = Offset + *AugmentationLength; |
1145 | break; |
1146 | case 'B': |
1147 | // B-Key is used for signing functions associated with this |
1148 | // augmentation string |
1149 | break; |
1150 | // This stack frame contains MTE tagged data, so needs to be |
1151 | // untagged on unwind. |
1152 | case 'G': |
1153 | break; |
1154 | } |
1155 | } |
1156 | |
1157 | if (AugmentationLength) { |
1158 | if (Offset != EndAugmentationOffset) |
1159 | return createStringError(EC: errc::invalid_argument, |
1160 | Fmt: "parsing augmentation data at 0x%" PRIx64 |
1161 | " failed" , |
1162 | Vals: StartOffset); |
1163 | AugmentationData = Data.getData().slice(Start: StartAugmentationOffset, |
1164 | End: EndAugmentationOffset); |
1165 | } |
1166 | } |
1167 | |
1168 | auto Cie = std::make_unique<CIE>( |
1169 | args&: IsDWARF64, args&: StartOffset, args&: Length, args&: Version, args&: AugmentationString, |
1170 | args&: AddressSize, args&: SegmentDescriptorSize, args&: CodeAlignmentFactor, |
1171 | args&: DataAlignmentFactor, args&: ReturnAddressRegister, args&: AugmentationData, |
1172 | args&: FDEPointerEncoding, args&: LSDAPointerEncoding, args&: Personality, |
1173 | args&: PersonalityEncoding, args: Arch); |
1174 | CIEs[StartOffset] = Cie.get(); |
1175 | Entries.emplace_back(args: std::move(Cie)); |
1176 | } else { |
1177 | // FDE |
1178 | uint64_t CIEPointer = Id; |
1179 | uint64_t InitialLocation = 0; |
1180 | uint64_t AddressRange = 0; |
1181 | std::optional<uint64_t> LSDAAddress; |
1182 | CIE *Cie = CIEs[IsEH ? (StartStructureOffset - CIEPointer) : CIEPointer]; |
1183 | |
1184 | if (IsEH) { |
1185 | // The address size is encoded in the CIE we reference. |
1186 | if (!Cie) |
1187 | return createStringError(EC: errc::invalid_argument, |
1188 | Fmt: "parsing FDE data at 0x%" PRIx64 |
1189 | " failed due to missing CIE" , |
1190 | Vals: StartOffset); |
1191 | if (auto Val = |
1192 | Data.getEncodedPointer(Offset: &Offset, Encoding: Cie->getFDEPointerEncoding(), |
1193 | AbsPosOffset: EHFrameAddress + Offset)) { |
1194 | InitialLocation = *Val; |
1195 | } |
1196 | if (auto Val = Data.getEncodedPointer( |
1197 | Offset: &Offset, Encoding: Cie->getFDEPointerEncoding(), AbsPosOffset: 0)) { |
1198 | AddressRange = *Val; |
1199 | } |
1200 | |
1201 | StringRef AugmentationString = Cie->getAugmentationString(); |
1202 | if (!AugmentationString.empty()) { |
1203 | // Parse the augmentation length and data for this FDE. |
1204 | uint64_t AugmentationLength = Data.getULEB128(offset_ptr: &Offset); |
1205 | |
1206 | uint64_t EndAugmentationOffset = Offset + AugmentationLength; |
1207 | |
1208 | // Decode the LSDA if the CIE augmentation string said we should. |
1209 | if (Cie->getLSDAPointerEncoding() != DW_EH_PE_omit) { |
1210 | LSDAAddress = Data.getEncodedPointer( |
1211 | Offset: &Offset, Encoding: Cie->getLSDAPointerEncoding(), |
1212 | AbsPosOffset: EHFrameAddress ? Offset + EHFrameAddress : 0); |
1213 | } |
1214 | |
1215 | if (Offset != EndAugmentationOffset) |
1216 | return createStringError(EC: errc::invalid_argument, |
1217 | Fmt: "parsing augmentation data at 0x%" PRIx64 |
1218 | " failed" , |
1219 | Vals: StartOffset); |
1220 | } |
1221 | } else { |
1222 | InitialLocation = Data.getRelocatedAddress(Off: &Offset); |
1223 | AddressRange = Data.getRelocatedAddress(Off: &Offset); |
1224 | } |
1225 | |
1226 | Entries.emplace_back(args: new FDE(IsDWARF64, StartOffset, Length, CIEPointer, |
1227 | InitialLocation, AddressRange, Cie, |
1228 | LSDAAddress, Arch)); |
1229 | } |
1230 | |
1231 | if (Error E = |
1232 | Entries.back()->cfis().parse(Data, Offset: &Offset, EndOffset: EndStructureOffset)) |
1233 | return E; |
1234 | |
1235 | if (Offset != EndStructureOffset) |
1236 | return createStringError( |
1237 | EC: errc::invalid_argument, |
1238 | Fmt: "parsing entry instructions at 0x%" PRIx64 " failed" , Vals: StartOffset); |
1239 | } |
1240 | |
1241 | return Error::success(); |
1242 | } |
1243 | |
1244 | FrameEntry *DWARFDebugFrame::getEntryAtOffset(uint64_t Offset) const { |
1245 | auto It = partition_point(Range: Entries, P: [=](const std::unique_ptr<FrameEntry> &E) { |
1246 | return E->getOffset() < Offset; |
1247 | }); |
1248 | if (It != Entries.end() && (*It)->getOffset() == Offset) |
1249 | return It->get(); |
1250 | return nullptr; |
1251 | } |
1252 | |
1253 | void DWARFDebugFrame::dump(raw_ostream &OS, DIDumpOptions DumpOpts, |
1254 | std::optional<uint64_t> Offset) const { |
1255 | DumpOpts.IsEH = IsEH; |
1256 | if (Offset) { |
1257 | if (auto *Entry = getEntryAtOffset(Offset: *Offset)) |
1258 | Entry->dump(OS, DumpOpts); |
1259 | return; |
1260 | } |
1261 | |
1262 | OS << "\n" ; |
1263 | for (const auto &Entry : Entries) |
1264 | Entry->dump(OS, DumpOpts); |
1265 | } |
1266 | |