1//===----------------------------------------------------------------------===//
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// Parses DWARF CFIs (FDEs and CIEs).
9//
10//===----------------------------------------------------------------------===//
11
12#ifndef __DWARF_PARSER_HPP__
13#define __DWARF_PARSER_HPP__
14
15#include <inttypes.h>
16#include <stdint.h>
17#include <stdio.h>
18#include <stdlib.h>
19
20#include "libunwind.h"
21#include "dwarf2.h"
22#include "Registers.hpp"
23
24#include "config.h"
25
26#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
27#include <ptrauth.h>
28#endif
29
30namespace libunwind {
31
32/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
33/// See DWARF Spec for details:
34/// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
35///
36template <typename A>
37class CFI_Parser {
38public:
39 typedef typename A::pint_t pint_t;
40 typedef pint_t __ptrauth_unwind_cie_info_personality personality_t;
41
42 /// Information encoded in a CIE (Common Information Entry)
43 struct CIE_Info {
44 pint_t cieStart;
45 pint_t cieLength;
46 pint_t cieInstructions;
47 uint8_t pointerEncoding;
48 uint8_t lsdaEncoding;
49 uint8_t personalityEncoding;
50 uint8_t personalityOffsetInCIE;
51 personality_t personality;
52 uint32_t codeAlignFactor;
53 int dataAlignFactor;
54 bool isSignalFrame;
55 bool fdesHaveAugmentationData;
56 uint8_t returnAddressRegister;
57#if defined(_LIBUNWIND_TARGET_AARCH64)
58 bool addressesSignedWithBKey;
59 bool mteTaggedFrame;
60#endif
61 };
62
63 /// Information about an FDE (Frame Description Entry)
64 struct FDE_Info {
65 pint_t fdeStart;
66 pint_t fdeLength;
67 pint_t fdeInstructions;
68 pint_t pcStart;
69 pint_t pcEnd;
70 pint_t lsda;
71 };
72
73 enum {
74 kMaxRegisterNumber = _LIBUNWIND_HIGHEST_DWARF_REGISTER
75 };
76 enum RegisterSavedWhere {
77 kRegisterUnused,
78 kRegisterUndefined,
79 kRegisterInCFA,
80 kRegisterInCFADecrypt, // sparc64 specific
81 kRegisterOffsetFromCFA,
82 kRegisterInRegister,
83 kRegisterAtExpression,
84 kRegisterIsExpression
85 };
86 struct RegisterLocation {
87 RegisterSavedWhere location;
88 bool initialStateSaved;
89 int64_t value;
90 };
91 /// Information about a frame layout and registers saved determined
92 /// by "running" the DWARF FDE "instructions"
93 struct PrologInfo {
94 uint32_t cfaRegister;
95 int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
96 int64_t cfaExpression; // CFA = expression
97 uint32_t spExtraArgSize;
98 RegisterLocation savedRegisters[kMaxRegisterNumber + 1];
99#if defined(_LIBUNWIND_TARGET_AARCH64)
100 pint_t ptrAuthDiversifier;
101#endif
102 enum class InitializeTime { kLazy, kNormal };
103
104 // When saving registers, this data structure is lazily initialized.
105 PrologInfo(InitializeTime IT = InitializeTime::kNormal) {
106 if (IT == InitializeTime::kNormal)
107 memset(this, 0, sizeof(*this));
108 }
109 void checkSaveRegister(uint64_t reg, PrologInfo &initialState) {
110 if (!savedRegisters[reg].initialStateSaved) {
111 initialState.savedRegisters[reg] = savedRegisters[reg];
112 savedRegisters[reg].initialStateSaved = true;
113 }
114 }
115 void setRegister(uint64_t reg, RegisterSavedWhere newLocation,
116 int64_t newValue, PrologInfo &initialState) {
117 checkSaveRegister(reg, initialState);
118 savedRegisters[reg].location = newLocation;
119 savedRegisters[reg].value = newValue;
120 }
121 void setRegisterLocation(uint64_t reg, RegisterSavedWhere newLocation,
122 PrologInfo &initialState) {
123 checkSaveRegister(reg, initialState);
124 savedRegisters[reg].location = newLocation;
125 }
126 void setRegisterValue(uint64_t reg, int64_t newValue,
127 PrologInfo &initialState) {
128 checkSaveRegister(reg, initialState);
129 savedRegisters[reg].value = newValue;
130 }
131 void restoreRegisterToInitialState(uint64_t reg, PrologInfo &initialState) {
132 if (savedRegisters[reg].initialStateSaved)
133 savedRegisters[reg] = initialState.savedRegisters[reg];
134 // else the register still holds its initial state
135 }
136 };
137
138 struct PrologInfoStackEntry {
139 PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i)
140 : next(n), info(i) {}
141 PrologInfoStackEntry *next;
142 PrologInfo info;
143 };
144
145 struct RememberStack {
146 PrologInfoStackEntry *entry;
147 RememberStack() : entry(nullptr) {}
148 ~RememberStack() {
149#if defined(_LIBUNWIND_REMEMBER_CLEANUP_NEEDED)
150 // Clean up rememberStack. Even in the case where every
151 // DW_CFA_remember_state is paired with a DW_CFA_restore_state,
152 // parseInstructions can skip restore opcodes if it reaches the target PC
153 // and stops interpreting, so we have to make sure we don't leak memory.
154 while (entry) {
155 PrologInfoStackEntry *next = entry->next;
156 _LIBUNWIND_REMEMBER_FREE(entry);
157 entry = next;
158 }
159#endif
160 }
161 };
162
163 template <typename R>
164 static bool findFDE(A &addressSpace, typename R::link_hardened_reg_arg_t pc,
165 pint_t ehSectionStart, size_t sectionLength,
166 pint_t fdeHint, FDE_Info *fdeInfo, CIE_Info *cieInfo);
167 static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
168 FDE_Info *fdeInfo, CIE_Info *cieInfo,
169 bool useCIEInfo = false);
170 template <typename R>
171 static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
172 const CIE_Info &cieInfo,
173 typename R::link_hardened_reg_arg_t upToPC,
174 int arch, PrologInfo *results);
175
176 static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
177};
178
179/// Parse a FDE into a CIE_Info and an FDE_Info. If useCIEInfo is
180/// true, treat cieInfo as already-parsed CIE_Info (whose start offset
181/// must match the one specified by the FDE) rather than parsing the
182/// one indicated within the FDE.
183template <typename A>
184const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
185 FDE_Info *fdeInfo, CIE_Info *cieInfo,
186 bool useCIEInfo) {
187 pint_t p = fdeStart;
188 pint_t cfiLength = (pint_t)addressSpace.get32(p);
189 p += 4;
190 if (cfiLength == 0xffffffff) {
191 // 0xffffffff means length is really next 8 bytes
192 cfiLength = (pint_t)addressSpace.get64(p);
193 p += 8;
194 }
195 if (cfiLength == 0)
196 return "FDE has zero length"; // zero terminator
197 uint32_t ciePointer = addressSpace.get32(p);
198 if (ciePointer == 0)
199 return "FDE is really a CIE"; // this is a CIE not an FDE
200 pint_t nextCFI = p + cfiLength;
201 pint_t cieStart = p - ciePointer;
202 if (useCIEInfo) {
203 if (cieInfo->cieStart != cieStart)
204 return "CIE start does not match";
205 } else {
206 const char *err = parseCIE(addressSpace, cie: cieStart, cieInfo);
207 if (err != NULL)
208 return err;
209 }
210 p += 4;
211 // Parse pc begin and range.
212 pint_t pcStart =
213 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
214 pint_t pcRange =
215 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
216 // Parse rest of info.
217 fdeInfo->lsda = 0;
218 // Check for augmentation length.
219 if (cieInfo->fdesHaveAugmentationData) {
220 pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
221 pint_t endOfAug = p + augLen;
222 if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
223 // Peek at value (without indirection). Zero means no LSDA.
224 pint_t lsdaStart = p;
225 if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) !=
226 0) {
227 // Reset pointer and re-parse LSDA address.
228 p = lsdaStart;
229 fdeInfo->lsda =
230 addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
231 }
232 }
233 p = endOfAug;
234 }
235 fdeInfo->fdeStart = fdeStart;
236 fdeInfo->fdeLength = nextCFI - fdeStart;
237 fdeInfo->fdeInstructions = p;
238 fdeInfo->pcStart = pcStart;
239 fdeInfo->pcEnd = pcStart + pcRange;
240 return NULL; // success
241}
242
243/// Scan an eh_frame section to find an FDE for a pc
244template <typename A>
245template <typename R>
246bool CFI_Parser<A>::findFDE(A &addressSpace,
247 typename R::link_hardened_reg_arg_t pc,
248 pint_t ehSectionStart, size_t sectionLength,
249 pint_t fdeHint, FDE_Info *fdeInfo,
250 CIE_Info *cieInfo) {
251 //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
252 pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
253 const pint_t ehSectionEnd = (sectionLength == SIZE_MAX)
254 ? static_cast<pint_t>(-1)
255 : (ehSectionStart + sectionLength);
256 while (p < ehSectionEnd) {
257 pint_t currentCFI = p;
258 //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
259 pint_t cfiLength = addressSpace.get32(p);
260 p += 4;
261 if (cfiLength == 0xffffffff) {
262 // 0xffffffff means length is really next 8 bytes
263 cfiLength = (pint_t)addressSpace.get64(p);
264 p += 8;
265 }
266 if (cfiLength == 0)
267 return false; // zero terminator
268 uint32_t id = addressSpace.get32(p);
269 if (id == 0) {
270 // Skip over CIEs.
271 p += cfiLength;
272 } else {
273 // Process FDE to see if it covers pc.
274 pint_t nextCFI = p + cfiLength;
275 uint32_t ciePointer = addressSpace.get32(p);
276 pint_t cieStart = p - ciePointer;
277 // Validate pointer to CIE is within section.
278 if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) {
279 if (parseCIE(addressSpace, cie: cieStart, cieInfo) == NULL) {
280 p += 4;
281 // Parse pc begin and range.
282 pint_t pcStart =
283 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
284 pint_t pcRange = addressSpace.getEncodedP(
285 p, nextCFI, cieInfo->pointerEncoding & 0x0F);
286 // Test if pc is within the function this FDE covers.
287 if ((pcStart <= pc) && (pc < pcStart + pcRange)) {
288 // parse rest of info
289 fdeInfo->lsda = 0;
290 // check for augmentation length
291 if (cieInfo->fdesHaveAugmentationData) {
292 pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
293 pint_t endOfAug = p + augLen;
294 if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
295 // Peek at value (without indirection). Zero means no LSDA.
296 pint_t lsdaStart = p;
297 if (addressSpace.getEncodedP(
298 p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) {
299 // Reset pointer and re-parse LSDA address.
300 p = lsdaStart;
301 fdeInfo->lsda = addressSpace
302 .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
303 }
304 }
305 p = endOfAug;
306 }
307 fdeInfo->fdeStart = currentCFI;
308 fdeInfo->fdeLength = nextCFI - currentCFI;
309 fdeInfo->fdeInstructions = p;
310 fdeInfo->pcStart = pcStart;
311 fdeInfo->pcEnd = pcStart + pcRange;
312 return true;
313 } else {
314 // pc is not in begin/range, skip this FDE
315 }
316 } else {
317 // Malformed CIE, now augmentation describing pc range encoding.
318 }
319 } else {
320 // malformed FDE. CIE is bad
321 }
322 p = nextCFI;
323 }
324 }
325 return false;
326}
327
328/// Extract info from a CIE
329template <typename A>
330const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
331 CIE_Info *cieInfo) {
332 cieInfo->pointerEncoding = 0;
333 cieInfo->lsdaEncoding = DW_EH_PE_omit;
334 cieInfo->personalityEncoding = 0;
335 cieInfo->personalityOffsetInCIE = 0;
336 cieInfo->personality = 0;
337 cieInfo->codeAlignFactor = 0;
338 cieInfo->dataAlignFactor = 0;
339 cieInfo->isSignalFrame = false;
340 cieInfo->fdesHaveAugmentationData = false;
341#if defined(_LIBUNWIND_TARGET_AARCH64)
342 cieInfo->addressesSignedWithBKey = false;
343 cieInfo->mteTaggedFrame = false;
344#endif
345 cieInfo->cieStart = cie;
346 pint_t p = cie;
347 pint_t cieLength = (pint_t)addressSpace.get32(p);
348 p += 4;
349 pint_t cieContentEnd = p + cieLength;
350 if (cieLength == 0xffffffff) {
351 // 0xffffffff means length is really next 8 bytes
352 cieLength = (pint_t)addressSpace.get64(p);
353 p += 8;
354 cieContentEnd = p + cieLength;
355 }
356 if (cieLength == 0)
357 return NULL;
358 // CIE ID is always 0
359 if (addressSpace.get32(p) != 0)
360 return "CIE ID is not zero";
361 p += 4;
362 // Version is always 1 or 3
363 uint8_t version = addressSpace.get8(p);
364 if ((version != 1) && (version != 3))
365 return "CIE version is not 1 or 3";
366 ++p;
367 // save start of augmentation string and find end
368 pint_t strStart = p;
369 while (addressSpace.get8(p) != 0)
370 ++p;
371 ++p;
372 // parse code alignment factor
373 cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd);
374 // parse data alignment factor
375 cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd);
376 // parse return address register
377 uint64_t raReg = (version == 1) ? addressSpace.get8(p++)
378 : addressSpace.getULEB128(p, cieContentEnd);
379 assert(raReg < 255 && "return address register too large");
380 cieInfo->returnAddressRegister = (uint8_t)raReg;
381 // parse augmentation data based on augmentation string
382 const char *result = NULL;
383 pint_t resultAddr = 0;
384 if (addressSpace.get8(strStart) == 'z') {
385 // parse augmentation data length
386 addressSpace.getULEB128(p, cieContentEnd);
387 for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) {
388 switch (addressSpace.get8(s)) {
389 case 'z':
390 cieInfo->fdesHaveAugmentationData = true;
391 break;
392 case 'P': {
393 cieInfo->personalityEncoding = addressSpace.get8(p);
394 ++p;
395 cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);
396 pint_t personality = addressSpace.getEncodedP(
397 p, cieContentEnd, cieInfo->personalityEncoding,
398 /*datarelBase=*/0, &resultAddr);
399#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
400 if (personality) {
401 // The GOT for the personality function was signed address
402 // authenticated. Manually re-sign with the CIE_Info::personality
403 // schema. If we could guarantee the encoding of the personality we
404 // could avoid this by simply giving resultAddr the correct ptrauth
405 // schema and performing an assignment.
406#if defined(__arm64e__)
407 const auto oldDiscriminator = resultAddr;
408#else
409 const auto oldDiscriminator = ptrauth_blend_discriminator(
410 (void *)resultAddr, __ptrauth_unwind_pauthtest_personality_disc);
411#endif
412 const auto discriminator = ptrauth_blend_discriminator(
413 &cieInfo->personality,
414 __ptrauth_unwind_cie_info_personality_disc);
415 void *signedPtr = ptrauth_auth_and_resign(
416 (void *)personality, ptrauth_key_function_pointer,
417 oldDiscriminator, ptrauth_key_function_pointer, discriminator);
418 personality = (pint_t)signedPtr;
419 }
420#endif
421 // We use memmove to set the CIE personality as we have already
422 // re-signed the pointer to the correct schema.
423 memmove(dest: (void *)&cieInfo->personality, src: (void *)&personality,
424 n: sizeof(personality));
425 break;
426 }
427 case 'L':
428 cieInfo->lsdaEncoding = addressSpace.get8(p);
429 ++p;
430 break;
431 case 'R':
432 cieInfo->pointerEncoding = addressSpace.get8(p);
433 ++p;
434 break;
435 case 'S':
436 cieInfo->isSignalFrame = true;
437 break;
438#if defined(_LIBUNWIND_TARGET_AARCH64)
439 case 'B':
440 cieInfo->addressesSignedWithBKey = true;
441 break;
442 case 'G':
443 cieInfo->mteTaggedFrame = true;
444 break;
445#endif
446 default:
447 // ignore unknown letters
448 break;
449 }
450 }
451 }
452 cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
453 cieInfo->cieInstructions = p;
454 return result;
455}
456
457
458/// "run" the DWARF instructions and create the abstract PrologInfo for an FDE
459template <typename A>
460template <typename R>
461bool CFI_Parser<A>::parseFDEInstructions(
462 A &addressSpace, const FDE_Info &fdeInfo, const CIE_Info &cieInfo,
463 typename R::link_hardened_reg_arg_t upToPC, int arch, PrologInfo *results) {
464 // Alloca is used for the allocation of the rememberStack entries. It removes
465 // the dependency on new/malloc but the below for loop can not be refactored
466 // into functions. Entry could be saved during the processing of a CIE and
467 // restored by an FDE.
468 RememberStack rememberStack;
469
470 struct ParseInfo {
471 pint_t instructions;
472 pint_t instructionsEnd;
473 pint_t pcoffset;
474 };
475
476 ParseInfo parseInfoArray[] = {
477 {cieInfo.cieInstructions, cieInfo.cieStart + cieInfo.cieLength,
478 (pint_t)(-1)},
479 {fdeInfo.fdeInstructions, fdeInfo.fdeStart + fdeInfo.fdeLength,
480 upToPC - fdeInfo.pcStart}};
481
482 for (const auto &info : parseInfoArray) {
483 pint_t p = info.instructions;
484 pint_t instructionsEnd = info.instructionsEnd;
485 pint_t pcoffset = info.pcoffset;
486 pint_t codeOffset = 0;
487
488 // initialState initialized as registers in results are modified. Use
489 // PrologInfo accessor functions to avoid reading uninitialized data.
490 PrologInfo initialState(PrologInfo::InitializeTime::kLazy);
491
492 _LIBUNWIND_TRACE_DWARF("parseFDEInstructions(instructions=0x%0" PRIx64
493 ")\n",
494 static_cast<uint64_t>(instructionsEnd));
495
496 // see DWARF Spec, section 6.4.2 for details on unwind opcodes
497 while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
498 uint64_t reg;
499 uint64_t reg2;
500 int64_t offset;
501 uint64_t length;
502 uint8_t opcode = addressSpace.get8(p);
503 uint8_t operand;
504
505 ++p;
506 switch (opcode) {
507 case DW_CFA_nop:
508 _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n");
509 break;
510 case DW_CFA_set_loc:
511 codeOffset = addressSpace.getEncodedP(p, instructionsEnd,
512 cieInfo.pointerEncoding);
513 _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n");
514 break;
515 case DW_CFA_advance_loc1:
516 codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
517 p += 1;
518 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",
519 static_cast<uint64_t>(codeOffset));
520 break;
521 case DW_CFA_advance_loc2:
522 codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
523 p += 2;
524 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",
525 static_cast<uint64_t>(codeOffset));
526 break;
527 case DW_CFA_advance_loc4:
528 codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
529 p += 4;
530 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",
531 static_cast<uint64_t>(codeOffset));
532 break;
533 case DW_CFA_offset_extended:
534 reg = addressSpace.getULEB128(p, instructionsEnd);
535 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
536 cieInfo.dataAlignFactor;
537 if (reg > kMaxRegisterNumber) {
538 _LIBUNWIND_LOG0(
539 "malformed DW_CFA_offset_extended DWARF unwind, reg too big");
540 return false;
541 }
542 results->setRegister(reg, kRegisterInCFA, offset, initialState);
543 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", "
544 "offset=%" PRId64 ")\n",
545 reg, offset);
546 break;
547 case DW_CFA_restore_extended:
548 reg = addressSpace.getULEB128(p, instructionsEnd);
549 if (reg > kMaxRegisterNumber) {
550 _LIBUNWIND_LOG0(
551 "malformed DW_CFA_restore_extended DWARF unwind, reg too big");
552 return false;
553 }
554 results->restoreRegisterToInitialState(reg, initialState);
555 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n",
556 reg);
557 break;
558 case DW_CFA_undefined:
559 reg = addressSpace.getULEB128(p, instructionsEnd);
560 if (reg > kMaxRegisterNumber) {
561 _LIBUNWIND_LOG0(
562 "malformed DW_CFA_undefined DWARF unwind, reg too big");
563 return false;
564 }
565 results->setRegisterLocation(reg, kRegisterUndefined, initialState);
566 _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
567 break;
568 case DW_CFA_same_value:
569 reg = addressSpace.getULEB128(p, instructionsEnd);
570 if (reg > kMaxRegisterNumber) {
571 _LIBUNWIND_LOG0(
572 "malformed DW_CFA_same_value DWARF unwind, reg too big");
573 return false;
574 }
575 // <rdar://problem/8456377> DW_CFA_same_value unsupported
576 // "same value" means register was stored in frame, but its current
577 // value has not changed, so no need to restore from frame.
578 // We model this as if the register was never saved.
579 results->setRegisterLocation(reg, kRegisterUnused, initialState);
580 _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);
581 break;
582 case DW_CFA_register:
583 reg = addressSpace.getULEB128(p, instructionsEnd);
584 reg2 = addressSpace.getULEB128(p, instructionsEnd);
585 if (reg > kMaxRegisterNumber) {
586 _LIBUNWIND_LOG0(
587 "malformed DW_CFA_register DWARF unwind, reg too big");
588 return false;
589 }
590 if (reg2 > kMaxRegisterNumber) {
591 _LIBUNWIND_LOG0(
592 "malformed DW_CFA_register DWARF unwind, reg2 too big");
593 return false;
594 }
595 results->setRegister(reg, kRegisterInRegister, (int64_t)reg2,
596 initialState);
597 _LIBUNWIND_TRACE_DWARF(
598 "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2);
599 break;
600 case DW_CFA_remember_state: {
601 // Avoid operator new because that would be an upward dependency.
602 // Avoid malloc because it needs heap allocation.
603 PrologInfoStackEntry *entry =
604 (PrologInfoStackEntry *)_LIBUNWIND_REMEMBER_ALLOC(
605 sizeof(PrologInfoStackEntry));
606 if (entry != NULL) {
607 entry->next = rememberStack.entry;
608 entry->info = *results;
609 rememberStack.entry = entry;
610 } else {
611 return false;
612 }
613 _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n");
614 break;
615 }
616 case DW_CFA_restore_state:
617 if (rememberStack.entry != NULL) {
618 PrologInfoStackEntry *top = rememberStack.entry;
619 *results = top->info;
620 rememberStack.entry = top->next;
621 _LIBUNWIND_REMEMBER_FREE(top);
622 } else {
623 return false;
624 }
625 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n");
626 break;
627 case DW_CFA_def_cfa:
628 reg = addressSpace.getULEB128(p, instructionsEnd);
629 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
630 if (reg > kMaxRegisterNumber) {
631 _LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big");
632 return false;
633 }
634 results->cfaRegister = (uint32_t)reg;
635 results->cfaRegisterOffset = (int32_t)offset;
636 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64
637 ")\n",
638 reg, offset);
639 break;
640 case DW_CFA_def_cfa_register:
641 reg = addressSpace.getULEB128(p, instructionsEnd);
642 if (reg > kMaxRegisterNumber) {
643 _LIBUNWIND_LOG0(
644 "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big");
645 return false;
646 }
647 results->cfaRegister = (uint32_t)reg;
648 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
649 break;
650 case DW_CFA_def_cfa_offset:
651 results->cfaRegisterOffset =
652 (int32_t)addressSpace.getULEB128(p, instructionsEnd);
653 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n",
654 results->cfaRegisterOffset);
655 break;
656 case DW_CFA_def_cfa_expression:
657 results->cfaRegister = 0;
658 results->cfaExpression = (int64_t)p;
659 length = addressSpace.getULEB128(p, instructionsEnd);
660 assert(length < static_cast<pint_t>(~0) && "pointer overflow");
661 p += static_cast<pint_t>(length);
662 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64
663 ", length=%" PRIu64 ")\n",
664 results->cfaExpression, length);
665 break;
666 case DW_CFA_expression:
667 reg = addressSpace.getULEB128(p, instructionsEnd);
668 if (reg > kMaxRegisterNumber) {
669 _LIBUNWIND_LOG0(
670 "malformed DW_CFA_expression DWARF unwind, reg too big");
671 return false;
672 }
673 results->setRegister(reg, kRegisterAtExpression, (int64_t)p,
674 initialState);
675 length = addressSpace.getULEB128(p, instructionsEnd);
676 assert(length < static_cast<pint_t>(~0) && "pointer overflow");
677 p += static_cast<pint_t>(length);
678 _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", "
679 "expression=0x%" PRIx64 ", "
680 "length=%" PRIu64 ")\n",
681 reg, results->savedRegisters[reg].value, length);
682 break;
683 case DW_CFA_offset_extended_sf:
684 reg = addressSpace.getULEB128(p, instructionsEnd);
685 if (reg > kMaxRegisterNumber) {
686 _LIBUNWIND_LOG0(
687 "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big");
688 return false;
689 }
690 offset = addressSpace.getSLEB128(p, instructionsEnd) *
691 cieInfo.dataAlignFactor;
692 results->setRegister(reg, kRegisterInCFA, offset, initialState);
693 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", "
694 "offset=%" PRId64 ")\n",
695 reg, offset);
696 break;
697 case DW_CFA_def_cfa_sf:
698 reg = addressSpace.getULEB128(p, instructionsEnd);
699 offset = addressSpace.getSLEB128(p, instructionsEnd) *
700 cieInfo.dataAlignFactor;
701 if (reg > kMaxRegisterNumber) {
702 _LIBUNWIND_LOG0(
703 "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big");
704 return false;
705 }
706 results->cfaRegister = (uint32_t)reg;
707 results->cfaRegisterOffset = (int32_t)offset;
708 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", "
709 "offset=%" PRId64 ")\n",
710 reg, offset);
711 break;
712 case DW_CFA_def_cfa_offset_sf:
713 results->cfaRegisterOffset =
714 (int32_t)(addressSpace.getSLEB128(p, instructionsEnd) *
715 cieInfo.dataAlignFactor);
716 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n",
717 results->cfaRegisterOffset);
718 break;
719 case DW_CFA_val_offset:
720 reg = addressSpace.getULEB128(p, instructionsEnd);
721 if (reg > kMaxRegisterNumber) {
722 _LIBUNWIND_LOG(
723 "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64
724 ") out of range\n",
725 reg);
726 return false;
727 }
728 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
729 cieInfo.dataAlignFactor;
730 results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);
731 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "
732 "offset=%" PRId64 "\n",
733 reg, offset);
734 break;
735 case DW_CFA_val_offset_sf:
736 reg = addressSpace.getULEB128(p, instructionsEnd);
737 if (reg > kMaxRegisterNumber) {
738 _LIBUNWIND_LOG0(
739 "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big");
740 return false;
741 }
742 offset = addressSpace.getSLEB128(p, instructionsEnd) *
743 cieInfo.dataAlignFactor;
744 results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);
745 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "
746 "offset=%" PRId64 "\n",
747 reg, offset);
748 break;
749 case DW_CFA_val_expression:
750 reg = addressSpace.getULEB128(p, instructionsEnd);
751 if (reg > kMaxRegisterNumber) {
752 _LIBUNWIND_LOG0(
753 "malformed DW_CFA_val_expression DWARF unwind, reg too big");
754 return false;
755 }
756 results->setRegister(reg, kRegisterIsExpression, (int64_t)p,
757 initialState);
758 length = addressSpace.getULEB128(p, instructionsEnd);
759 assert(length < static_cast<pint_t>(~0) && "pointer overflow");
760 p += static_cast<pint_t>(length);
761 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "
762 "expression=0x%" PRIx64 ", length=%" PRIu64
763 ")\n",
764 reg, results->savedRegisters[reg].value, length);
765 break;
766 case DW_CFA_GNU_args_size:
767 length = addressSpace.getULEB128(p, instructionsEnd);
768 results->spExtraArgSize = (uint32_t)length;
769 _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
770 break;
771 case DW_CFA_GNU_negative_offset_extended:
772 reg = addressSpace.getULEB128(p, instructionsEnd);
773 if (reg > kMaxRegisterNumber) {
774 _LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF "
775 "unwind, reg too big");
776 return false;
777 }
778 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
779 cieInfo.dataAlignFactor;
780 results->setRegister(reg, kRegisterInCFA, -offset, initialState);
781 _LIBUNWIND_TRACE_DWARF(
782 "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
783 break;
784
785#if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC) || \
786 defined(_LIBUNWIND_TARGET_SPARC64)
787 // The same constant is used to represent different instructions on
788 // AArch64 (negate_ra_state) and SPARC (window_save).
789 static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save,
790 "uses the same constant");
791 case DW_CFA_AARCH64_negate_ra_state:
792 switch (arch) {
793#if defined(_LIBUNWIND_TARGET_AARCH64)
794 case REGISTERS_ARM64: {
795 int64_t value =
796 results->savedRegisters[UNW_AARCH64_RA_SIGN_STATE].value ^ 0x1;
797 results->setRegisterValue(UNW_AARCH64_RA_SIGN_STATE, value,
798 initialState);
799 _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n");
800 } break;
801#endif
802
803#if defined(_LIBUNWIND_TARGET_SPARC)
804 // case DW_CFA_GNU_window_save:
805 case REGISTERS_SPARC:
806 _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n");
807 for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) {
808 results->setRegister(reg, kRegisterInRegister,
809 ((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0,
810 initialState);
811 }
812
813 for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {
814 results->setRegister(reg, kRegisterInCFA,
815 ((int64_t)reg - UNW_SPARC_L0) * 4,
816 initialState);
817 }
818 break;
819#endif
820
821#if defined(_LIBUNWIND_TARGET_SPARC64)
822 // case DW_CFA_GNU_window_save:
823 case REGISTERS_SPARC64:
824 // Don't save %o0-%o7 on sparc64.
825 // https://reviews.llvm.org/D32450#736405
826
827 for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {
828 if (reg == UNW_SPARC_I7)
829 results->setRegister(
830 reg, kRegisterInCFADecrypt,
831 static_cast<int64_t>((reg - UNW_SPARC_L0) * sizeof(pint_t)),
832 initialState);
833 else
834 results->setRegister(
835 reg, kRegisterInCFA,
836 static_cast<int64_t>((reg - UNW_SPARC_L0) * sizeof(pint_t)),
837 initialState);
838 }
839 _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save\n");
840 break;
841#endif
842 }
843 break;
844
845#if defined(_LIBUNWIND_TARGET_AARCH64)
846 case DW_CFA_AARCH64_negate_ra_state_with_pc: {
847 int64_t value =
848 results->savedRegisters[UNW_AARCH64_RA_SIGN_STATE].value ^ 0x3;
849 results->setRegisterValue(UNW_AARCH64_RA_SIGN_STATE, value,
850 initialState);
851 // When using Feat_PAuthLR, the PC value needs to be captured so that
852 // during unwinding, the correct PC value is used for re-authentication.
853 // It is assumed that the CFI is placed before the signing instruction.
854 results->ptrAuthDiversifier = fdeInfo.pcStart + codeOffset;
855 _LIBUNWIND_TRACE_DWARF(
856 "DW_CFA_AARCH64_negate_ra_state_with_pc(pc=0x%" PRIx64 ")\n",
857 static_cast<uint64_t>(results->ptrAuthDiversifier));
858 } break;
859#endif
860
861#else
862 (void)arch;
863#endif
864
865 default:
866 operand = opcode & 0x3F;
867 switch (opcode & 0xC0) {
868 case DW_CFA_offset:
869 reg = operand;
870 if (reg > kMaxRegisterNumber) {
871 _LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64
872 ") out of range",
873 reg);
874 return false;
875 }
876 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
877 cieInfo.dataAlignFactor;
878 results->setRegister(reg, kRegisterInCFA, offset, initialState);
879 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
880 operand, offset);
881 break;
882 case DW_CFA_advance_loc:
883 codeOffset += operand * cieInfo.codeAlignFactor;
884 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
885 static_cast<uint64_t>(codeOffset));
886 break;
887 case DW_CFA_restore:
888 reg = operand;
889 if (reg > kMaxRegisterNumber) {
890 _LIBUNWIND_LOG(
891 "malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64
892 ") out of range",
893 reg);
894 return false;
895 }
896 results->restoreRegisterToInitialState(reg, initialState);
897 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",
898 static_cast<uint64_t>(operand));
899 break;
900 default:
901 _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);
902 return false;
903 }
904 }
905 }
906 }
907 return true;
908}
909
910} // namespace libunwind
911
912#endif // __DWARF_PARSER_HPP__
913