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