1 //===--------------------------- DwarfParser.hpp --------------------------===//
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
8 // Parses DWARF CFIs (FDEs and CIEs).
10 //===----------------------------------------------------------------------===//
12 #ifndef __DWARF_PARSER_HPP__
13 #define __DWARF_PARSER_HPP__
20 #include "libunwind.h"
22 #include "Registers.hpp"
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
35 typedef typename A::pint_t pint_t;
37 /// Information encoded in a CIE (Common Information Entry)
41 pint_t cieInstructions;
42 uint8_t pointerEncoding;
44 uint8_t personalityEncoding;
45 uint8_t personalityOffsetInCIE;
47 uint32_t codeAlignFactor;
50 bool fdesHaveAugmentationData;
51 uint8_t returnAddressRegister;
52 #if defined(_LIBUNWIND_TARGET_AARCH64)
53 bool addressesSignedWithBKey;
57 /// Information about an FDE (Frame Description Entry)
61 pint_t fdeInstructions;
68 kMaxRegisterNumber = _LIBUNWIND_HIGHEST_DWARF_REGISTER
70 enum RegisterSavedWhere {
73 kRegisterOffsetFromCFA,
75 kRegisterAtExpression,
78 struct RegisterLocation {
79 RegisterSavedWhere location;
82 /// Information about a frame layout and registers saved determined
83 /// by "running" the DWARF FDE "instructions"
86 int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
87 int64_t cfaExpression; // CFA = expression
88 uint32_t spExtraArgSize;
89 uint32_t codeOffsetAtStackDecrement;
90 bool registersInOtherRegisters;
92 RegisterLocation savedRegisters[kMaxRegisterNumber + 1];
95 struct PrologInfoStackEntry {
96 PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i)
98 PrologInfoStackEntry *next;
102 static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
103 uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
105 static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
106 FDE_Info *fdeInfo, CIE_Info *cieInfo);
107 static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
108 const CIE_Info &cieInfo, pint_t upToPC,
109 int arch, PrologInfo *results);
111 static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
114 static bool parseInstructions(A &addressSpace, pint_t instructions,
115 pint_t instructionsEnd, const CIE_Info &cieInfo,
117 PrologInfoStackEntry *&rememberStack, int arch,
118 PrologInfo *results);
121 /// Parse a FDE into a CIE_Info and an FDE_Info
122 template <typename A>
123 const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
124 FDE_Info *fdeInfo, CIE_Info *cieInfo) {
126 pint_t cfiLength = (pint_t)addressSpace.get32(p);
128 if (cfiLength == 0xffffffff) {
129 // 0xffffffff means length is really next 8 bytes
130 cfiLength = (pint_t)addressSpace.get64(p);
134 return "FDE has zero length"; // end marker
135 uint32_t ciePointer = addressSpace.get32(p);
137 return "FDE is really a CIE"; // this is a CIE not an FDE
138 pint_t nextCFI = p + cfiLength;
139 pint_t cieStart = p - ciePointer;
140 const char *err = parseCIE(addressSpace, cieStart, cieInfo);
144 // Parse pc begin and range.
146 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
148 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
149 // Parse rest of info.
151 // Check for augmentation length.
152 if (cieInfo->fdesHaveAugmentationData) {
153 pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
154 pint_t endOfAug = p + augLen;
155 if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
156 // Peek at value (without indirection). Zero means no LSDA.
157 pint_t lsdaStart = p;
158 if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) !=
160 // Reset pointer and re-parse LSDA address.
163 addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
168 fdeInfo->fdeStart = fdeStart;
169 fdeInfo->fdeLength = nextCFI - fdeStart;
170 fdeInfo->fdeInstructions = p;
171 fdeInfo->pcStart = pcStart;
172 fdeInfo->pcEnd = pcStart + pcRange;
173 return NULL; // success
176 /// Scan an eh_frame section to find an FDE for a pc
177 template <typename A>
178 bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
179 uint32_t sectionLength, pint_t fdeHint,
180 FDE_Info *fdeInfo, CIE_Info *cieInfo) {
181 //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
182 pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
183 const pint_t ehSectionEnd = p + sectionLength;
184 while (p < ehSectionEnd) {
185 pint_t currentCFI = p;
186 //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
187 pint_t cfiLength = addressSpace.get32(p);
189 if (cfiLength == 0xffffffff) {
190 // 0xffffffff means length is really next 8 bytes
191 cfiLength = (pint_t)addressSpace.get64(p);
195 return false; // end marker
196 uint32_t id = addressSpace.get32(p);
201 // Process FDE to see if it covers pc.
202 pint_t nextCFI = p + cfiLength;
203 uint32_t ciePointer = addressSpace.get32(p);
204 pint_t cieStart = p - ciePointer;
205 // Validate pointer to CIE is within section.
206 if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) {
207 if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) {
209 // Parse pc begin and range.
211 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
212 pint_t pcRange = addressSpace.getEncodedP(
213 p, nextCFI, cieInfo->pointerEncoding & 0x0F);
214 // Test if pc is within the function this FDE covers.
215 if ((pcStart < pc) && (pc <= pcStart + pcRange)) {
216 // parse rest of info
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(
226 p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) {
227 // Reset pointer and re-parse LSDA address.
229 fdeInfo->lsda = addressSpace
230 .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
235 fdeInfo->fdeStart = currentCFI;
236 fdeInfo->fdeLength = nextCFI - currentCFI;
237 fdeInfo->fdeInstructions = p;
238 fdeInfo->pcStart = pcStart;
239 fdeInfo->pcEnd = pcStart + pcRange;
242 // pc is not in begin/range, skip this FDE
245 // Malformed CIE, now augmentation describing pc range encoding.
248 // malformed FDE. CIE is bad
256 /// Extract info from a CIE
257 template <typename A>
258 const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
260 cieInfo->pointerEncoding = 0;
261 cieInfo->lsdaEncoding = DW_EH_PE_omit;
262 cieInfo->personalityEncoding = 0;
263 cieInfo->personalityOffsetInCIE = 0;
264 cieInfo->personality = 0;
265 cieInfo->codeAlignFactor = 0;
266 cieInfo->dataAlignFactor = 0;
267 cieInfo->isSignalFrame = false;
268 cieInfo->fdesHaveAugmentationData = false;
269 #if defined(_LIBUNWIND_TARGET_AARCH64)
270 cieInfo->addressesSignedWithBKey = false;
272 cieInfo->cieStart = cie;
274 pint_t cieLength = (pint_t)addressSpace.get32(p);
276 pint_t cieContentEnd = p + cieLength;
277 if (cieLength == 0xffffffff) {
278 // 0xffffffff means length is really next 8 bytes
279 cieLength = (pint_t)addressSpace.get64(p);
281 cieContentEnd = p + cieLength;
285 // CIE ID is always 0
286 if (addressSpace.get32(p) != 0)
287 return "CIE ID is not zero";
289 // Version is always 1 or 3
290 uint8_t version = addressSpace.get8(p);
291 if ((version != 1) && (version != 3))
292 return "CIE version is not 1 or 3";
294 // save start of augmentation string and find end
296 while (addressSpace.get8(p) != 0)
299 // parse code aligment factor
300 cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd);
301 // parse data alignment factor
302 cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd);
303 // parse return address register
304 uint64_t raReg = addressSpace.getULEB128(p, cieContentEnd);
305 assert(raReg < 255 && "return address register too large");
306 cieInfo->returnAddressRegister = (uint8_t)raReg;
307 // parse augmentation data based on augmentation string
308 const char *result = NULL;
309 if (addressSpace.get8(strStart) == 'z') {
310 // parse augmentation data length
311 addressSpace.getULEB128(p, cieContentEnd);
312 for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) {
313 switch (addressSpace.get8(s)) {
315 cieInfo->fdesHaveAugmentationData = true;
318 cieInfo->personalityEncoding = addressSpace.get8(p);
320 cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);
321 cieInfo->personality = addressSpace
322 .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
325 cieInfo->lsdaEncoding = addressSpace.get8(p);
329 cieInfo->pointerEncoding = addressSpace.get8(p);
333 cieInfo->isSignalFrame = true;
335 #if defined(_LIBUNWIND_TARGET_AARCH64)
337 cieInfo->addressesSignedWithBKey = true;
341 // ignore unknown letters
346 cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
347 cieInfo->cieInstructions = p;
352 /// "run" the DWARF instructions and create the abstact PrologInfo for an FDE
353 template <typename A>
354 bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
355 const FDE_Info &fdeInfo,
356 const CIE_Info &cieInfo, pint_t upToPC,
357 int arch, PrologInfo *results) {
359 memset(results, '\0', sizeof(PrologInfo));
360 PrologInfoStackEntry *rememberStack = NULL;
362 // parse CIE then FDE instructions
363 return parseInstructions(addressSpace, cieInfo.cieInstructions,
364 cieInfo.cieStart + cieInfo.cieLength, cieInfo,
365 (pint_t)(-1), rememberStack, arch, results) &&
366 parseInstructions(addressSpace, fdeInfo.fdeInstructions,
367 fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo,
368 upToPC - fdeInfo.pcStart, rememberStack, arch,
372 /// "run" the DWARF instructions
373 template <typename A>
374 bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
375 pint_t instructionsEnd,
376 const CIE_Info &cieInfo, pint_t pcoffset,
377 PrologInfoStackEntry *&rememberStack,
378 int arch, PrologInfo *results) {
379 pint_t p = instructions;
380 pint_t codeOffset = 0;
381 PrologInfo initialState = *results;
383 _LIBUNWIND_TRACE_DWARF("parseInstructions(instructions=0x%0" PRIx64 ")\n",
384 static_cast<uint64_t>(instructionsEnd));
386 // see DWARF Spec, section 6.4.2 for details on unwind opcodes
387 while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
392 uint8_t opcode = addressSpace.get8(p);
394 #if !defined(_LIBUNWIND_NO_HEAP)
395 PrologInfoStackEntry *entry;
400 _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n");
404 addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
405 _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n");
407 case DW_CFA_advance_loc1:
408 codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
410 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",
411 static_cast<uint64_t>(codeOffset));
413 case DW_CFA_advance_loc2:
414 codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
416 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",
417 static_cast<uint64_t>(codeOffset));
419 case DW_CFA_advance_loc4:
420 codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
422 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",
423 static_cast<uint64_t>(codeOffset));
425 case DW_CFA_offset_extended:
426 reg = addressSpace.getULEB128(p, instructionsEnd);
427 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
428 * cieInfo.dataAlignFactor;
429 if (reg > kMaxRegisterNumber) {
431 "malformed DW_CFA_offset_extended DWARF unwind, reg too big");
434 results->savedRegisters[reg].location = kRegisterInCFA;
435 results->savedRegisters[reg].value = offset;
436 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", "
437 "offset=%" PRId64 ")\n",
440 case DW_CFA_restore_extended:
441 reg = addressSpace.getULEB128(p, instructionsEnd);
442 if (reg > kMaxRegisterNumber) {
444 "malformed DW_CFA_restore_extended DWARF unwind, reg too big");
447 results->savedRegisters[reg] = initialState.savedRegisters[reg];
448 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg);
450 case DW_CFA_undefined:
451 reg = addressSpace.getULEB128(p, instructionsEnd);
452 if (reg > kMaxRegisterNumber) {
454 "malformed DW_CFA_undefined DWARF unwind, reg too big");
457 results->savedRegisters[reg].location = kRegisterUnused;
458 _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
460 case DW_CFA_same_value:
461 reg = addressSpace.getULEB128(p, instructionsEnd);
462 if (reg > kMaxRegisterNumber) {
464 "malformed DW_CFA_same_value DWARF unwind, reg too big");
467 // <rdar://problem/8456377> DW_CFA_same_value unsupported
468 // "same value" means register was stored in frame, but its current
469 // value has not changed, so no need to restore from frame.
470 // We model this as if the register was never saved.
471 results->savedRegisters[reg].location = kRegisterUnused;
472 // set flag to disable conversion to compact unwind
473 results->sameValueUsed = true;
474 _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);
476 case DW_CFA_register:
477 reg = addressSpace.getULEB128(p, instructionsEnd);
478 reg2 = addressSpace.getULEB128(p, instructionsEnd);
479 if (reg > kMaxRegisterNumber) {
481 "malformed DW_CFA_register DWARF unwind, reg too big");
484 if (reg2 > kMaxRegisterNumber) {
486 "malformed DW_CFA_register DWARF unwind, reg2 too big");
489 results->savedRegisters[reg].location = kRegisterInRegister;
490 results->savedRegisters[reg].value = (int64_t)reg2;
491 // set flag to disable conversion to compact unwind
492 results->registersInOtherRegisters = true;
493 _LIBUNWIND_TRACE_DWARF(
494 "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2);
496 #if !defined(_LIBUNWIND_NO_HEAP)
497 case DW_CFA_remember_state:
498 // avoid operator new, because that would be an upward dependency
499 entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry));
501 entry->next = rememberStack;
502 entry->info = *results;
503 rememberStack = entry;
507 _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n");
509 case DW_CFA_restore_state:
510 if (rememberStack != NULL) {
511 PrologInfoStackEntry *top = rememberStack;
512 *results = top->info;
513 rememberStack = top->next;
518 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n");
522 reg = addressSpace.getULEB128(p, instructionsEnd);
523 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
524 if (reg > kMaxRegisterNumber) {
525 _LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big");
528 results->cfaRegister = (uint32_t)reg;
529 results->cfaRegisterOffset = (int32_t)offset;
530 _LIBUNWIND_TRACE_DWARF(
531 "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", reg, offset);
533 case DW_CFA_def_cfa_register:
534 reg = addressSpace.getULEB128(p, instructionsEnd);
535 if (reg > kMaxRegisterNumber) {
537 "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big");
540 results->cfaRegister = (uint32_t)reg;
541 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
543 case DW_CFA_def_cfa_offset:
544 results->cfaRegisterOffset = (int32_t)
545 addressSpace.getULEB128(p, instructionsEnd);
546 results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
547 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n",
548 results->cfaRegisterOffset);
550 case DW_CFA_def_cfa_expression:
551 results->cfaRegister = 0;
552 results->cfaExpression = (int64_t)p;
553 length = addressSpace.getULEB128(p, instructionsEnd);
554 assert(length < static_cast<pint_t>(~0) && "pointer overflow");
555 p += static_cast<pint_t>(length);
556 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64
557 ", length=%" PRIu64 ")\n",
558 results->cfaExpression, length);
560 case DW_CFA_expression:
561 reg = addressSpace.getULEB128(p, instructionsEnd);
562 if (reg > kMaxRegisterNumber) {
564 "malformed DW_CFA_expression DWARF unwind, reg too big");
567 results->savedRegisters[reg].location = kRegisterAtExpression;
568 results->savedRegisters[reg].value = (int64_t)p;
569 length = addressSpace.getULEB128(p, instructionsEnd);
570 assert(length < static_cast<pint_t>(~0) && "pointer overflow");
571 p += static_cast<pint_t>(length);
572 _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", "
573 "expression=0x%" PRIx64 ", "
574 "length=%" PRIu64 ")\n",
575 reg, results->savedRegisters[reg].value, length);
577 case DW_CFA_offset_extended_sf:
578 reg = addressSpace.getULEB128(p, instructionsEnd);
579 if (reg > kMaxRegisterNumber) {
581 "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big");
585 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
586 results->savedRegisters[reg].location = kRegisterInCFA;
587 results->savedRegisters[reg].value = offset;
588 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", "
589 "offset=%" PRId64 ")\n",
592 case DW_CFA_def_cfa_sf:
593 reg = addressSpace.getULEB128(p, instructionsEnd);
595 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
596 if (reg > kMaxRegisterNumber) {
598 "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big");
601 results->cfaRegister = (uint32_t)reg;
602 results->cfaRegisterOffset = (int32_t)offset;
603 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", "
604 "offset=%" PRId64 ")\n",
607 case DW_CFA_def_cfa_offset_sf:
608 results->cfaRegisterOffset = (int32_t)
609 (addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor);
610 results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
611 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n",
612 results->cfaRegisterOffset);
614 case DW_CFA_val_offset:
615 reg = addressSpace.getULEB128(p, instructionsEnd);
616 if (reg > kMaxRegisterNumber) {
618 "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64
623 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
624 * cieInfo.dataAlignFactor;
625 results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
626 results->savedRegisters[reg].value = offset;
627 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "
628 "offset=%" PRId64 "\n",
631 case DW_CFA_val_offset_sf:
632 reg = addressSpace.getULEB128(p, instructionsEnd);
633 if (reg > kMaxRegisterNumber) {
635 "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big");
639 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
640 results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
641 results->savedRegisters[reg].value = offset;
642 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "
643 "offset=%" PRId64 "\n",
646 case DW_CFA_val_expression:
647 reg = addressSpace.getULEB128(p, instructionsEnd);
648 if (reg > kMaxRegisterNumber) {
650 "malformed DW_CFA_val_expression DWARF unwind, reg too big");
653 results->savedRegisters[reg].location = kRegisterIsExpression;
654 results->savedRegisters[reg].value = (int64_t)p;
655 length = addressSpace.getULEB128(p, instructionsEnd);
656 assert(length < static_cast<pint_t>(~0) && "pointer overflow");
657 p += static_cast<pint_t>(length);
658 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "
659 "expression=0x%" PRIx64 ", length=%" PRIu64 ")\n",
660 reg, results->savedRegisters[reg].value, length);
662 case DW_CFA_GNU_args_size:
663 length = addressSpace.getULEB128(p, instructionsEnd);
664 results->spExtraArgSize = (uint32_t)length;
665 _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
667 case DW_CFA_GNU_negative_offset_extended:
668 reg = addressSpace.getULEB128(p, instructionsEnd);
669 if (reg > kMaxRegisterNumber) {
670 _LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF "
671 "unwind, reg too big");
674 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
675 * cieInfo.dataAlignFactor;
676 results->savedRegisters[reg].location = kRegisterInCFA;
677 results->savedRegisters[reg].value = -offset;
678 _LIBUNWIND_TRACE_DWARF(
679 "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
682 #if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC)
683 // The same constant is used to represent different instructions on
684 // AArch64 (negate_ra_state) and SPARC (window_save).
685 static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save,
686 "uses the same constant");
687 case DW_CFA_AARCH64_negate_ra_state:
689 #if defined(_LIBUNWIND_TARGET_AARCH64)
690 case REGISTERS_ARM64:
691 results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^= 0x1;
692 _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n");
695 #if defined(_LIBUNWIND_TARGET_SPARC)
696 // case DW_CFA_GNU_window_save:
697 case REGISTERS_SPARC:
698 _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n");
699 for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) {
700 results->savedRegisters[reg].location = kRegisterInRegister;
701 results->savedRegisters[reg].value =
702 ((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0;
705 for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {
706 results->savedRegisters[reg].location = kRegisterInCFA;
707 results->savedRegisters[reg].value =
708 ((int64_t)reg - UNW_SPARC_L0) * 4;
719 operand = opcode & 0x3F;
720 switch (opcode & 0xC0) {
723 if (reg > kMaxRegisterNumber) {
724 _LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64
729 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
730 * cieInfo.dataAlignFactor;
731 results->savedRegisters[reg].location = kRegisterInCFA;
732 results->savedRegisters[reg].value = offset;
733 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
736 case DW_CFA_advance_loc:
737 codeOffset += operand * cieInfo.codeAlignFactor;
738 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
739 static_cast<uint64_t>(codeOffset));
743 if (reg > kMaxRegisterNumber) {
744 _LIBUNWIND_LOG("malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64
749 results->savedRegisters[reg] = initialState.savedRegisters[reg];
750 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",
751 static_cast<uint64_t>(operand));
754 _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);
763 } // namespace libunwind
765 #endif // __DWARF_PARSER_HPP__