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