1 //===--------------------------- DwarfParser.hpp --------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
9 // Parses DWARF CFIs (FDEs and CIEs).
11 //===----------------------------------------------------------------------===//
13 #ifndef __DWARF_PARSER_HPP__
14 #define __DWARF_PARSER_HPP__
21 #include "libunwind.h"
24 #include "AddressSpace.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;
54 /// Information about an FDE (Frame Description Entry)
58 pint_t fdeInstructions;
65 kMaxRegisterNumber = _LIBUNWIND_MAX_REGISTER
67 enum RegisterSavedWhere {
70 kRegisterOffsetFromCFA,
72 kRegisterAtExpression,
75 struct RegisterLocation {
76 RegisterSavedWhere location;
79 /// Information about a frame layout and registers saved determined
80 /// by "running" the dwarf FDE "instructions"
83 int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
84 int64_t cfaExpression; // CFA = expression
85 uint32_t spExtraArgSize;
86 uint32_t codeOffsetAtStackDecrement;
87 bool registersInOtherRegisters;
89 RegisterLocation savedRegisters[kMaxRegisterNumber];
92 struct PrologInfoStackEntry {
93 PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i)
95 PrologInfoStackEntry *next;
99 static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
100 uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
102 static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
103 FDE_Info *fdeInfo, CIE_Info *cieInfo);
104 static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
105 const CIE_Info &cieInfo, pint_t upToPC,
106 PrologInfo *results);
108 static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
111 static bool parseInstructions(A &addressSpace, pint_t instructions,
112 pint_t instructionsEnd, const CIE_Info &cieInfo,
114 PrologInfoStackEntry *&rememberStack,
115 PrologInfo *results);
118 /// Parse a FDE into a CIE_Info and an FDE_Info
119 template <typename A>
120 const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
121 FDE_Info *fdeInfo, CIE_Info *cieInfo) {
123 pint_t cfiLength = (pint_t)addressSpace.get32(p);
125 if (cfiLength == 0xffffffff) {
126 // 0xffffffff means length is really next 8 bytes
127 cfiLength = (pint_t)addressSpace.get64(p);
131 return "FDE has zero length"; // end marker
132 uint32_t ciePointer = addressSpace.get32(p);
134 return "FDE is really a CIE"; // this is a CIE not an FDE
135 pint_t nextCFI = p + cfiLength;
136 pint_t cieStart = p - ciePointer;
137 const char *err = parseCIE(addressSpace, cieStart, cieInfo);
141 // parse pc begin and range
143 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
145 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
146 // parse rest of info
148 // check for augmentation length
149 if (cieInfo->fdesHaveAugmentationData) {
150 pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
151 pint_t endOfAug = p + augLen;
152 if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
153 // peek at value (without indirection). Zero means no lsda
154 pint_t lsdaStart = p;
155 if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) !=
157 // reset pointer and re-parse lsda address
160 addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
165 fdeInfo->fdeStart = fdeStart;
166 fdeInfo->fdeLength = nextCFI - fdeStart;
167 fdeInfo->fdeInstructions = p;
168 fdeInfo->pcStart = pcStart;
169 fdeInfo->pcEnd = pcStart + pcRange;
170 return NULL; // success
173 /// Scan an eh_frame section to find an FDE for a pc
174 template <typename A>
175 bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
176 uint32_t sectionLength, pint_t fdeHint,
177 FDE_Info *fdeInfo, CIE_Info *cieInfo) {
178 //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
179 pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
180 const pint_t ehSectionEnd = p + sectionLength;
181 while (p < ehSectionEnd) {
182 pint_t currentCFI = p;
183 //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
184 pint_t cfiLength = addressSpace.get32(p);
186 if (cfiLength == 0xffffffff) {
187 // 0xffffffff means length is really next 8 bytes
188 cfiLength = (pint_t)addressSpace.get64(p);
192 return false; // end marker
193 uint32_t id = addressSpace.get32(p);
198 // process FDE to see if it covers pc
199 pint_t nextCFI = p + cfiLength;
200 uint32_t ciePointer = addressSpace.get32(p);
201 pint_t cieStart = p - ciePointer;
202 // validate pointer to CIE is within section
203 if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) {
204 if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) {
206 // parse pc begin and range
208 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
209 pint_t pcRange = addressSpace.getEncodedP(
210 p, nextCFI, cieInfo->pointerEncoding & 0x0F);
211 // test if pc is within the function this FDE covers
212 if ((pcStart < pc) && (pc <= pcStart + pcRange)) {
213 // parse rest of info
215 // check for augmentation length
216 if (cieInfo->fdesHaveAugmentationData) {
217 pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
218 pint_t endOfAug = p + augLen;
219 if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
220 // peek at value (without indirection). Zero means no lsda
221 pint_t lsdaStart = p;
222 if (addressSpace.getEncodedP(
223 p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) {
224 // reset pointer and re-parse lsda address
226 fdeInfo->lsda = addressSpace
227 .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
232 fdeInfo->fdeStart = currentCFI;
233 fdeInfo->fdeLength = nextCFI - currentCFI;
234 fdeInfo->fdeInstructions = p;
235 fdeInfo->pcStart = pcStart;
236 fdeInfo->pcEnd = pcStart + pcRange;
239 // pc is not in begin/range, skip this FDE
242 // malformed CIE, now augmentation describing pc range encoding
245 // malformed FDE. CIE is bad
253 /// Extract info from a CIE
254 template <typename A>
255 const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
257 cieInfo->pointerEncoding = 0;
258 cieInfo->lsdaEncoding = DW_EH_PE_omit;
259 cieInfo->personalityEncoding = 0;
260 cieInfo->personalityOffsetInCIE = 0;
261 cieInfo->personality = 0;
262 cieInfo->codeAlignFactor = 0;
263 cieInfo->dataAlignFactor = 0;
264 cieInfo->isSignalFrame = false;
265 cieInfo->fdesHaveAugmentationData = false;
266 cieInfo->cieStart = cie;
268 pint_t cieLength = (pint_t)addressSpace.get32(p);
270 pint_t cieContentEnd = p + cieLength;
271 if (cieLength == 0xffffffff) {
272 // 0xffffffff means length is really next 8 bytes
273 cieLength = (pint_t)addressSpace.get64(p);
275 cieContentEnd = p + cieLength;
279 // CIE ID is always 0
280 if (addressSpace.get32(p) != 0)
281 return "CIE ID is not zero";
283 // Version is always 1 or 3
284 uint8_t version = addressSpace.get8(p);
285 if ((version != 1) && (version != 3))
286 return "CIE version is not 1 or 3";
288 // save start of augmentation string and find end
290 while (addressSpace.get8(p) != 0)
293 // parse code aligment factor
294 cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd);
295 // parse data alignment factor
296 cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd);
297 // parse return address register
298 uint64_t raReg = addressSpace.getULEB128(p, cieContentEnd);
299 assert(raReg < 255 && "return address register too large");
300 cieInfo->returnAddressRegister = (uint8_t)raReg;
301 // parse augmentation data based on augmentation string
302 const char *result = NULL;
303 if (addressSpace.get8(strStart) == 'z') {
304 // parse augmentation data length
305 addressSpace.getULEB128(p, cieContentEnd);
306 for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) {
307 switch (addressSpace.get8(s)) {
309 cieInfo->fdesHaveAugmentationData = true;
312 cieInfo->personalityEncoding = addressSpace.get8(p);
314 cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);
315 cieInfo->personality = addressSpace
316 .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
319 cieInfo->lsdaEncoding = addressSpace.get8(p);
323 cieInfo->pointerEncoding = addressSpace.get8(p);
327 cieInfo->isSignalFrame = true;
330 // ignore unknown letters
335 cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
336 cieInfo->cieInstructions = p;
341 /// "run" the dwarf instructions and create the abstact PrologInfo for an FDE
342 template <typename A>
343 bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
344 const FDE_Info &fdeInfo,
345 const CIE_Info &cieInfo, pint_t upToPC,
346 PrologInfo *results) {
348 memset(results, '\0', sizeof(PrologInfo));
349 PrologInfoStackEntry *rememberStack = NULL;
351 // parse CIE then FDE instructions
352 return parseInstructions(addressSpace, cieInfo.cieInstructions,
353 cieInfo.cieStart + cieInfo.cieLength, cieInfo,
354 (pint_t)(-1), rememberStack, results) &&
355 parseInstructions(addressSpace, fdeInfo.fdeInstructions,
356 fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo,
357 upToPC - fdeInfo.pcStart, rememberStack, results);
360 /// "run" the dwarf instructions
361 template <typename A>
362 bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
363 pint_t instructionsEnd,
364 const CIE_Info &cieInfo, pint_t pcoffset,
365 PrologInfoStackEntry *&rememberStack,
366 PrologInfo *results) {
367 const bool logDwarf = false;
368 pint_t p = instructions;
369 pint_t codeOffset = 0;
370 PrologInfo initialState = *results;
372 fprintf(stderr, "parseInstructions(instructions=0x%0" PRIx64 ")\n",
373 (uint64_t)instructionsEnd);
375 // see Dwarf Spec, section 6.4.2 for details on unwind opcodes
376 while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
381 uint8_t opcode = addressSpace.get8(p);
383 #if !defined(_LIBUNWIND_NO_HEAP)
384 PrologInfoStackEntry *entry;
390 fprintf(stderr, "DW_CFA_nop\n");
394 addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
396 fprintf(stderr, "DW_CFA_set_loc\n");
398 case DW_CFA_advance_loc1:
399 codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
402 fprintf(stderr, "DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",
403 (uint64_t)codeOffset);
405 case DW_CFA_advance_loc2:
406 codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
409 fprintf(stderr, "DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",
410 (uint64_t)codeOffset);
412 case DW_CFA_advance_loc4:
413 codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
416 fprintf(stderr, "DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",
417 (uint64_t)codeOffset);
419 case DW_CFA_offset_extended:
420 reg = addressSpace.getULEB128(p, instructionsEnd);
421 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
422 * cieInfo.dataAlignFactor;
423 if (reg > kMaxRegisterNumber) {
425 "malformed DW_CFA_offset_extended dwarf unwind, reg too big\n");
428 results->savedRegisters[reg].location = kRegisterInCFA;
429 results->savedRegisters[reg].value = offset;
432 "DW_CFA_offset_extended(reg=%" PRIu64 ", offset=%" PRId64 ")\n",
435 case DW_CFA_restore_extended:
436 reg = addressSpace.getULEB128(p, instructionsEnd);
438 if (reg > kMaxRegisterNumber) {
441 "malformed DW_CFA_restore_extended dwarf unwind, reg too big\n");
444 results->savedRegisters[reg] = initialState.savedRegisters[reg];
446 fprintf(stderr, "DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg);
448 case DW_CFA_undefined:
449 reg = addressSpace.getULEB128(p, instructionsEnd);
450 if (reg > kMaxRegisterNumber) {
452 "malformed DW_CFA_undefined dwarf unwind, reg too big\n");
455 results->savedRegisters[reg].location = kRegisterUnused;
457 fprintf(stderr, "DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
459 case DW_CFA_same_value:
460 reg = addressSpace.getULEB128(p, instructionsEnd);
461 if (reg > kMaxRegisterNumber) {
463 "malformed DW_CFA_same_value dwarf unwind, reg too big\n");
466 // <rdar://problem/8456377> DW_CFA_same_value unsupported
467 // "same value" means register was stored in frame, but its current
468 // value has not changed, so no need to restore from frame.
469 // We model this as if the register was never saved.
470 results->savedRegisters[reg].location = kRegisterUnused;
471 // set flag to disable conversion to compact unwind
472 results->sameValueUsed = true;
474 fprintf(stderr, "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\n");
484 if (reg2 > kMaxRegisterNumber) {
486 "malformed DW_CFA_register dwarf unwind, reg2 too big\n");
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;
494 fprintf(stderr, "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n",
497 #if !defined(_LIBUNWIND_NO_HEAP)
498 case DW_CFA_remember_state:
499 // avoid operator new, because that would be an upward dependency
500 entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry));
502 entry->next = rememberStack;
503 entry->info = *results;
504 rememberStack = entry;
509 fprintf(stderr, "DW_CFA_remember_state\n");
511 case DW_CFA_restore_state:
512 if (rememberStack != NULL) {
513 PrologInfoStackEntry *top = rememberStack;
514 *results = top->info;
515 rememberStack = top->next;
521 fprintf(stderr, "DW_CFA_restore_state\n");
525 reg = addressSpace.getULEB128(p, instructionsEnd);
526 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
527 if (reg > kMaxRegisterNumber) {
528 fprintf(stderr, "malformed DW_CFA_def_cfa dwarf unwind, reg too big\n");
531 results->cfaRegister = (uint32_t)reg;
532 results->cfaRegisterOffset = (int32_t)offset;
534 fprintf(stderr, "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n",
537 case DW_CFA_def_cfa_register:
538 reg = addressSpace.getULEB128(p, instructionsEnd);
539 if (reg > kMaxRegisterNumber) {
542 "malformed DW_CFA_def_cfa_register dwarf unwind, reg too big\n");
545 results->cfaRegister = (uint32_t)reg;
547 fprintf(stderr, "DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
549 case DW_CFA_def_cfa_offset:
550 results->cfaRegisterOffset = (int32_t)
551 addressSpace.getULEB128(p, instructionsEnd);
552 results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
554 fprintf(stderr, "DW_CFA_def_cfa_offset(%d)\n",
555 results->cfaRegisterOffset);
557 case DW_CFA_def_cfa_expression:
558 results->cfaRegister = 0;
559 results->cfaExpression = (int64_t)p;
560 length = addressSpace.getULEB128(p, instructionsEnd);
563 fprintf(stderr, "DW_CFA_def_cfa_expression(expression=0x%" PRIx64
564 ", length=%" PRIu64 ")\n",
565 results->cfaExpression, length);
567 case DW_CFA_expression:
568 reg = addressSpace.getULEB128(p, instructionsEnd);
569 if (reg > kMaxRegisterNumber) {
571 "malformed DW_CFA_expression dwarf unwind, reg too big\n");
574 results->savedRegisters[reg].location = kRegisterAtExpression;
575 results->savedRegisters[reg].value = (int64_t)p;
576 length = addressSpace.getULEB128(p, instructionsEnd);
579 fprintf(stderr, "DW_CFA_expression(reg=%" PRIu64
580 ", expression=0x%" PRIx64 ", length=%" PRIu64 ")\n",
581 reg, results->savedRegisters[reg].value, length);
583 case DW_CFA_offset_extended_sf:
584 reg = addressSpace.getULEB128(p, instructionsEnd);
585 if (reg > kMaxRegisterNumber) {
588 "malformed DW_CFA_offset_extended_sf dwarf unwind, reg too big\n");
592 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
593 results->savedRegisters[reg].location = kRegisterInCFA;
594 results->savedRegisters[reg].value = offset;
596 fprintf(stderr, "DW_CFA_offset_extended_sf(reg=%" PRIu64
597 ", offset=%" PRId64 ")\n",
600 case DW_CFA_def_cfa_sf:
601 reg = addressSpace.getULEB128(p, instructionsEnd);
603 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
604 if (reg > kMaxRegisterNumber) {
606 "malformed DW_CFA_def_cfa_sf dwarf unwind, reg too big\n");
609 results->cfaRegister = (uint32_t)reg;
610 results->cfaRegisterOffset = (int32_t)offset;
613 "DW_CFA_def_cfa_sf(reg=%" PRIu64 ", offset=%" PRId64 ")\n", reg,
616 case DW_CFA_def_cfa_offset_sf:
617 results->cfaRegisterOffset = (int32_t)
618 (addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor);
619 results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
621 fprintf(stderr, "DW_CFA_def_cfa_offset_sf(%d)\n",
622 results->cfaRegisterOffset);
624 case DW_CFA_val_offset:
625 reg = addressSpace.getULEB128(p, instructionsEnd);
626 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
627 * cieInfo.dataAlignFactor;
628 results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
629 results->savedRegisters[reg].value = offset;
632 "DW_CFA_val_offset(reg=%" PRIu64 ", offset=%" PRId64 "\n", reg,
635 case DW_CFA_val_offset_sf:
636 reg = addressSpace.getULEB128(p, instructionsEnd);
637 if (reg > kMaxRegisterNumber) {
639 "malformed DW_CFA_val_offset_sf dwarf unwind, reg too big\n");
643 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
644 results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
645 results->savedRegisters[reg].value = offset;
648 "DW_CFA_val_offset_sf(reg=%" PRIu64 ", offset=%" PRId64 "\n",
651 case DW_CFA_val_expression:
652 reg = addressSpace.getULEB128(p, instructionsEnd);
653 if (reg > kMaxRegisterNumber) {
655 "malformed DW_CFA_val_expression dwarf unwind, reg too big\n");
658 results->savedRegisters[reg].location = kRegisterIsExpression;
659 results->savedRegisters[reg].value = (int64_t)p;
660 length = addressSpace.getULEB128(p, instructionsEnd);
663 fprintf(stderr, "DW_CFA_val_expression(reg=%" PRIu64
664 ", expression=0x%" PRIx64 ", length=%" PRIu64 ")\n",
665 reg, results->savedRegisters[reg].value, length);
667 case DW_CFA_GNU_args_size:
668 length = addressSpace.getULEB128(p, instructionsEnd);
669 results->spExtraArgSize = (uint32_t)length;
671 fprintf(stderr, "DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
673 case DW_CFA_GNU_negative_offset_extended:
674 reg = addressSpace.getULEB128(p, instructionsEnd);
675 if (reg > kMaxRegisterNumber) {
676 fprintf(stderr, "malformed DW_CFA_GNU_negative_offset_extended dwarf "
677 "unwind, reg too big\n");
680 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
681 * cieInfo.dataAlignFactor;
682 results->savedRegisters[reg].location = kRegisterInCFA;
683 results->savedRegisters[reg].value = -offset;
685 fprintf(stderr, "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n",
689 operand = opcode & 0x3F;
690 switch (opcode & 0xC0) {
693 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
694 * cieInfo.dataAlignFactor;
695 results->savedRegisters[reg].location = kRegisterInCFA;
696 results->savedRegisters[reg].value = offset;
698 fprintf(stderr, "DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
701 case DW_CFA_advance_loc:
702 codeOffset += operand * cieInfo.codeAlignFactor;
704 fprintf(stderr, "DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
705 (uint64_t)codeOffset);
709 results->savedRegisters[reg] = initialState.savedRegisters[reg];
711 fprintf(stderr, "DW_CFA_restore(reg=%" PRIu64 ")\n", reg);
715 fprintf(stderr, "unknown CFA opcode 0x%02X\n", opcode);
724 } // namespace libunwind
726 #endif // __DWARF_PARSER_HPP__