1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2008 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
26 // processor specific parsing of dwarf unwind instructions
29 #ifndef __DWARF_PARSER_HPP__
30 #define __DWARF_PARSER_HPP__
38 #include "libunwind.h"
41 #include "AddressSpace.hpp"
48 /// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
49 /// See Dwarf Spec for details:
50 /// http://www.linux-foundation.org/spec/booksets/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
56 typedef typename A::pint_t pint_t;
59 /// Information encoded in a CIE (Common Information Entry)
64 pint_t cieInstructions;
65 uint8_t pointerEncoding;
67 uint8_t personalityEncoding;
68 uint8_t personalityOffsetInCIE;
73 bool fdesHaveAugmentationData;
77 /// Information about an FDE (Frame Description Entry)
82 pint_t fdeInstructions;
89 /// Used by linker when parsing __eh_frame section
91 struct FDE_Reference {
94 uint8_t encodingOfAddress;
96 struct FDE_Atom_Info {
98 FDE_Reference function;
102 struct CIE_Atom_Info {
104 FDE_Reference personality;
109 /// Information about a frame layout and registers saved determined
110 /// by "running" the dwarf FDE "instructions"
112 enum { kMaxRegisterNumber = 120 };
113 enum RegisterSavedWhere { kRegisterUnused, kRegisterInCFA, kRegisterOffsetFromCFA,
114 kRegisterInRegister, kRegisterAtExpression, kRegisterIsExpression } ;
115 struct RegisterLocation {
116 RegisterSavedWhere location;
120 uint32_t cfaRegister;
121 int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
122 int64_t cfaExpression; // CFA = expression
123 uint32_t spExtraArgSize;
124 uint32_t codeOffsetAtStackDecrement;
125 uint8_t registerSavedTwiceInCIE;
126 bool registersInOtherRegisters;
127 bool registerSavedMoreThanOnce;
128 bool cfaOffsetWasNegative;
130 RegisterLocation savedRegisters[kMaxRegisterNumber]; // from where to restore registers
133 struct PrologInfoStackEntry {
134 PrologInfoStackEntry(PrologInfoStackEntry* n, const PrologInfo& i)
135 : next(n), info(i) {}
136 PrologInfoStackEntry* next;
140 static bool findFDE(A& addressSpace, pint_t pc, pint_t ehSectionStart, uint32_t sectionLength, pint_t fdeHint, FDE_Info* fdeInfo, CIE_Info* cieInfo);
141 static const char* decodeFDE(A& addressSpace, pint_t fdeStart, FDE_Info* fdeInfo, CIE_Info* cieInfo);
142 static bool parseFDEInstructions(A& addressSpace, const FDE_Info& fdeInfo, const CIE_Info& cieInfo, pint_t upToPC, PrologInfo* results);
143 static const char* getCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength,
144 std::vector<FDE_Atom_Info>& fdes, std::vector<CIE_Atom_Info>& cies);
145 static uint32_t getCFICount(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength);
147 static const char* parseCIE(A& addressSpace, pint_t cie, CIE_Info* cieInfo);
150 static bool parseInstructions(A& addressSpace, pint_t instructions, pint_t instructionsEnd, const CIE_Info& cieInfo,
151 pint_t pcoffset, PrologInfoStackEntry*& rememberStack, PrologInfo* results);
156 /// Parse a FDE into a CIE_Info and an FDE_Info
158 template <typename A>
159 const char* CFI_Parser<A>::decodeFDE(A& addressSpace, pint_t fdeStart, FDE_Info* fdeInfo, CIE_Info* cieInfo)
162 uint64_t cfiLength = addressSpace.get32(p);
164 if ( cfiLength == 0xffffffff ) {
165 // 0xffffffff means length is really next 8 bytes
166 cfiLength = addressSpace.get64(p);
169 if ( cfiLength == 0 )
170 return "FDE has zero length"; // end marker
171 uint32_t ciePointer = addressSpace.get32(p);
172 if ( ciePointer == 0 )
173 return "FDE is really a CIE"; // this is a CIE not an FDE
174 pint_t nextCFI = p + cfiLength;
175 pint_t cieStart = p-ciePointer;
176 const char* err = parseCIE(addressSpace, cieStart, cieInfo);
180 // parse pc begin and range
181 pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
182 pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
183 // parse rest of info
185 // check for augmentation length
186 if ( cieInfo->fdesHaveAugmentationData ) {
187 uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
188 pint_t endOfAug = p + augLen;
189 if ( cieInfo->lsdaEncoding != 0 ) {
190 // peek at value (without indirection). Zero means no lsda
191 pint_t lsdaStart = p;
192 if ( addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0 ) {
193 // reset pointer and re-parse lsda address
195 fdeInfo->lsda = addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
200 fdeInfo->fdeStart = fdeStart;
201 fdeInfo->fdeLength = nextCFI - fdeStart;
202 fdeInfo->fdeInstructions = p;
203 fdeInfo->pcStart = pcStart;
204 fdeInfo->pcEnd = pcStart+pcRange;
205 return NULL; // success
210 /// Scan an eh_frame section to find an FDE for a pc
212 template <typename A>
213 bool CFI_Parser<A>::findFDE(A& addressSpace, pint_t pc, pint_t ehSectionStart, uint32_t sectionLength, pint_t fdeHint, FDE_Info* fdeInfo, CIE_Info* cieInfo)
215 //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
216 pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
217 const pint_t ehSectionEnd = p + sectionLength;
218 while ( p < ehSectionEnd ) {
219 pint_t currentCFI = p;
220 //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
221 uint64_t cfiLength = addressSpace.get32(p);
223 if ( cfiLength == 0xffffffff ) {
224 // 0xffffffff means length is really next 8 bytes
225 cfiLength = addressSpace.get64(p);
228 if ( cfiLength == 0 )
229 return false; // end marker
230 uint32_t id = addressSpace.get32(p);
236 // process FDE to see if it covers pc
237 pint_t nextCFI = p + cfiLength;
238 uint32_t ciePointer = addressSpace.get32(p);
239 pint_t cieStart = p-ciePointer;
240 // validate pointer to CIE is within section
241 if ( (ehSectionStart <= cieStart) && (cieStart < ehSectionEnd) ) {
242 if ( parseCIE(addressSpace, cieStart, cieInfo) == NULL ) {
244 // parse pc begin and range
245 pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
246 pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
247 //fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
248 // test if pc is within the function this FDE covers
249 if ( (pcStart < pc) && (pc <= pcStart+pcRange) ) {
250 // parse rest of info
252 // check for augmentation length
253 if ( cieInfo->fdesHaveAugmentationData ) {
254 uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
255 pint_t endOfAug = p + augLen;
256 if ( cieInfo->lsdaEncoding != 0 ) {
257 // peek at value (without indirection). Zero means no lsda
258 pint_t lsdaStart = p;
259 if ( addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0 ) {
260 // reset pointer and re-parse lsda address
262 fdeInfo->lsda = addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
267 fdeInfo->fdeStart = currentCFI;
268 fdeInfo->fdeLength = nextCFI - currentCFI;
269 fdeInfo->fdeInstructions = p;
270 fdeInfo->pcStart = pcStart;
271 fdeInfo->pcEnd = pcStart+pcRange;
272 //fprintf(stderr, "findFDE(pc=0x%llX) found with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pc, (uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
276 //fprintf(stderr, "findFDE(pc=0x%llX) not found with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pc, (uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
277 // pc is not in begin/range, skip this FDE
281 // malformed CIE, now augmentation describing pc range encoding
282 //fprintf(stderr, "malformed CIE\n");
286 // malformed FDE. CIE is bad
287 //fprintf(stderr, "malformed FDE, cieStart=0x%llX, ehSectionStart=0x%llX, ehSectionEnd=0x%llX\n",
288 // (uint64_t)cieStart, (uint64_t)ehSectionStart, (uint64_t)ehSectionEnd);
293 //fprintf(stderr, "findFDE(pc=0x%llX) not found\n",(uint64_t)pc);
300 /// Extract info from a CIE
302 template <typename A>
303 const char* CFI_Parser<A>::parseCIE(A& addressSpace, pint_t cie, CIE_Info* cieInfo)
305 //fprintf(stderr, "parseCIE(0x%llX)\n", (long long)cie);
306 cieInfo->pointerEncoding = 0;
307 cieInfo->lsdaEncoding = 0;
308 cieInfo->personalityEncoding = 0;
309 cieInfo->personalityOffsetInCIE = 0;
310 cieInfo->personality = 0;
311 cieInfo->codeAlignFactor = 0;
312 cieInfo->dataAlignFactor = 0;
313 cieInfo->isSignalFrame = false;
314 cieInfo->fdesHaveAugmentationData = false;
315 cieInfo->cieStart = cie;
317 uint64_t cieLength = addressSpace.get32(p);
319 pint_t cieContentEnd = p + cieLength;
320 if ( cieLength == 0xffffffff ) {
321 // 0xffffffff means length is really next 8 bytes
322 cieLength = addressSpace.get64(p);
324 cieContentEnd = p + cieLength;
326 if ( cieLength == 0 )
328 // CIE ID is always 0
329 if ( addressSpace.get32(p) != 0 )
330 return "CIE ID is not zero";
332 // Version is always 1 or 3
333 uint8_t version = addressSpace.get8(p);
334 if ( (version != 1) && (version != 3) )
335 return "CIE version is not 1 or 3";
337 // save start of augmentation string and find end
339 while ( addressSpace.get8(p) != 0 )
342 // parse code aligment factor
343 cieInfo->codeAlignFactor = addressSpace.getULEB128(p, cieContentEnd);
344 // parse data alignment factor
345 cieInfo->dataAlignFactor = addressSpace.getSLEB128(p, cieContentEnd);
346 // parse return address register
347 addressSpace.getULEB128(p, cieContentEnd);
348 // parse augmentation data based on augmentation string
349 const char* result = NULL;
350 if ( addressSpace.get8(strStart) == 'z' ) {
351 // parse augmentation data length
352 addressSpace.getULEB128(p, cieContentEnd);
353 for (pint_t s=strStart; addressSpace.get8(s) != '\0'; ++s) {
354 switch ( addressSpace.get8(s) ) {
356 cieInfo->fdesHaveAugmentationData = true;
359 cieInfo->personalityEncoding = addressSpace.get8(p);
361 cieInfo->personalityOffsetInCIE = p-cie;
362 cieInfo->personality = addressSpace.getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
365 cieInfo->lsdaEncoding = addressSpace.get8(p);
369 cieInfo->pointerEncoding = addressSpace.get8(p);
373 cieInfo->isSignalFrame = true;
376 // ignore unknown letters
381 cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
382 cieInfo->cieInstructions = p;
387 template <typename A>
388 uint32_t CFI_Parser<A>::getCFICount(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength)
391 const pint_t ehSectionEnd = ehSectionStart + sectionLength;
392 for (pint_t p=ehSectionStart; p < ehSectionEnd; ) {
393 uint64_t cfiLength = addressSpace.get32(p);
395 if ( cfiLength == 0xffffffff ) {
396 // 0xffffffff means length is really next 8 bytes
397 cfiLength = addressSpace.get64(p);
400 if ( cfiLength == 0 )
401 return count; // end marker
410 template <typename A>
411 const char* CFI_Parser<A>::getCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength,
412 std::vector<FDE_Atom_Info>& fdes, std::vector<CIE_Atom_Info>& cies)
414 const pint_t ehSectionEnd = ehSectionStart + sectionLength;
415 for (pint_t p=ehSectionStart; p < ehSectionEnd; ) {
416 pint_t currentCFI = p;
417 uint64_t cfiLength = addressSpace.get32(p);
419 if ( cfiLength == 0xffffffff ) {
420 // 0xffffffff means length is really next 8 bytes
421 cfiLength = addressSpace.get64(p);
424 if ( cfiLength == 0 )
425 return NULL; // end marker
426 uint32_t id = addressSpace.get32(p);
430 const char* err = parseCIE(addressSpace, currentCFI, &cieInfo);
434 entry.cieAddress = currentCFI;
435 entry.personality.address = cieInfo.personality;
436 entry.personality.offsetInFDE = cieInfo.personalityOffsetInCIE;
437 entry.personality.encodingOfAddress = cieInfo.personalityEncoding;
438 cies.push_back(entry);
444 entry.fdeAddress = currentCFI;
445 entry.function.address = 0;
446 entry.cie.address = 0;
447 entry.lsda.address = 0;
448 pint_t nextCFI = p + cfiLength;
449 uint32_t ciePointer = addressSpace.get32(p);
450 pint_t cieStart = p-ciePointer;
451 // validate pointer to CIE is within section
452 if ( (cieStart < ehSectionStart) || (cieStart > ehSectionEnd) )
453 return "FDE points to CIE outside __eh_frame section";
455 const char* err = parseCIE(addressSpace, cieStart, &cieInfo);
458 entry.cie.address = cieStart;
459 entry.cie.offsetInFDE = p-currentCFI;
460 entry.cie.encodingOfAddress = DW_EH_PE_sdata4 | DW_EH_PE_pcrel;
462 // parse pc begin and range
463 pint_t offsetOfFunctionAddress = p-currentCFI;
464 pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding);
465 pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding & 0x0F);
466 //fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
467 // test if pc is within the function this FDE covers
468 entry.function.address = pcStart;
469 entry.function.offsetInFDE = offsetOfFunctionAddress;
470 entry.function.encodingOfAddress = cieInfo.pointerEncoding;
471 // skip over augmentation length
472 if ( cieInfo.fdesHaveAugmentationData ) {
473 uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
474 pint_t endOfAug = p + augLen;
475 if ( (cieInfo.lsdaEncoding != 0) && (addressSpace.getP(p) != 0) ) {
476 pint_t offsetOfLSDAAddress = p-currentCFI;
477 entry.lsda.address = addressSpace.getEncodedP(p, nextCFI, cieInfo.lsdaEncoding);
478 entry.lsda.offsetInFDE = offsetOfLSDAAddress;
479 entry.lsda.encodingOfAddress = cieInfo.lsdaEncoding;
483 fdes.push_back(entry);
487 return NULL; // success
493 /// "run" the dwarf instructions and create the abstact PrologInfo for an FDE
495 template <typename A>
496 bool CFI_Parser<A>::parseFDEInstructions(A& addressSpace, const FDE_Info& fdeInfo, const CIE_Info& cieInfo, pint_t upToPC, PrologInfo* results)
499 bzero(results, sizeof(PrologInfo));
500 PrologInfoStackEntry* rememberStack = NULL;
502 // parse CIE then FDE instructions
503 return parseInstructions(addressSpace, cieInfo.cieInstructions, cieInfo.cieStart+cieInfo.cieLength,
504 cieInfo, (pint_t)(-1), rememberStack, results)
505 && parseInstructions(addressSpace, fdeInfo.fdeInstructions, fdeInfo.fdeStart+fdeInfo.fdeLength,
506 cieInfo, upToPC-fdeInfo.pcStart, rememberStack, results);
511 /// "run" the dwarf instructions
513 template <typename A>
514 bool CFI_Parser<A>::parseInstructions(A& addressSpace, pint_t instructions, pint_t instructionsEnd, const CIE_Info& cieInfo,
515 pint_t pcoffset, PrologInfoStackEntry*& rememberStack, PrologInfo* results)
517 const bool logDwarf = false;
518 pint_t p = instructions;
519 uint32_t codeOffset = 0;
520 PrologInfo initialState = *results;
521 if ( logDwarf ) fprintf(stderr, "parseInstructions(instructions=0x%0llX)\n", (uint64_t)instructionsEnd);
523 // see Dwarf Spec, section 6.4.2 for details on unwind opcodes
524 while ( (p < instructionsEnd) && (codeOffset < pcoffset) ) {
529 uint8_t opcode = addressSpace.get8(p);
531 PrologInfoStackEntry* entry;
535 if ( logDwarf ) fprintf(stderr, "DW_CFA_nop\n");
538 codeOffset = addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
539 if ( logDwarf ) fprintf(stderr, "DW_CFA_set_loc\n");
541 case DW_CFA_advance_loc1:
542 codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
544 if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc1: new offset=%u\n", codeOffset);
546 case DW_CFA_advance_loc2:
547 codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
549 if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc2: new offset=%u\n", codeOffset);
551 case DW_CFA_advance_loc4:
552 codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
554 if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc4: new offset=%u\n", codeOffset);
556 case DW_CFA_offset_extended:
557 reg = addressSpace.getULEB128(p, instructionsEnd);
558 offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
559 if ( reg > kMaxRegisterNumber ) {
560 fprintf(stderr, "malformed DW_CFA_offset_extended dwarf unwind, reg too big\n");
563 if ( results->savedRegisters[reg].location != kRegisterUnused )
564 results->registerSavedMoreThanOnce = true;
565 results->savedRegisters[reg].location = kRegisterInCFA;
566 results->savedRegisters[reg].value = offset;
567 if ( logDwarf ) fprintf(stderr, "DW_CFA_offset_extended(reg=%lld, offset=%lld)\n", reg, offset);
569 case DW_CFA_restore_extended:
570 reg = addressSpace.getULEB128(p, instructionsEnd);;
571 if ( reg > kMaxRegisterNumber ) {
572 fprintf(stderr, "malformed DW_CFA_restore_extended dwarf unwind, reg too big\n");
575 results->savedRegisters[reg] = initialState.savedRegisters[reg];
576 if ( logDwarf ) fprintf(stderr, "DW_CFA_restore_extended(reg=%lld)\n", reg);
578 case DW_CFA_undefined:
579 reg = addressSpace.getULEB128(p, instructionsEnd);
580 if ( reg > kMaxRegisterNumber ) {
581 fprintf(stderr, "malformed DW_CFA_undefined dwarf unwind, reg too big\n");
584 results->savedRegisters[reg].location = kRegisterUnused;
585 if ( logDwarf ) fprintf(stderr, "DW_CFA_undefined(reg=%lld)\n", reg);
587 case DW_CFA_same_value:
588 reg = addressSpace.getULEB128(p, instructionsEnd);
589 if ( reg > kMaxRegisterNumber ) {
590 fprintf(stderr, "malformed DW_CFA_same_value dwarf unwind, reg too big\n");
593 // <rdar://problem/8456377> DW_CFA_same_value unsupported
594 // "same value" means register was stored in frame, but its current
595 // value has not changed, so no need to restore from frame.
596 // We model this as if the register was never saved.
597 results->savedRegisters[reg].location = kRegisterUnused;
598 // set flag to disable conversion to compact unwind
599 results->sameValueUsed = true;
600 if ( logDwarf ) fprintf(stderr, "DW_CFA_same_value(reg=%lld)\n", reg);
602 case DW_CFA_register:
603 reg = addressSpace.getULEB128(p, instructionsEnd);
604 reg2 = addressSpace.getULEB128(p, instructionsEnd);
605 if ( reg > kMaxRegisterNumber ) {
606 fprintf(stderr, "malformed DW_CFA_register dwarf unwind, reg too big\n");
609 if ( reg2 > kMaxRegisterNumber ) {
610 fprintf(stderr, "malformed DW_CFA_register dwarf unwind, reg2 too big\n");
613 results->savedRegisters[reg].location = kRegisterInRegister;
614 results->savedRegisters[reg].value = reg2;
615 // set flag to disable conversion to compact unwind
616 results->registersInOtherRegisters = true;
617 if ( logDwarf ) fprintf(stderr, "DW_CFA_register(reg=%lld, reg2=%lld)\n", reg, reg2);
619 case DW_CFA_remember_state:
620 // avoid operator new, because that would be an upward dependency
621 entry = (PrologInfoStackEntry*)malloc(sizeof(PrologInfoStackEntry));
622 if ( entry != NULL ) {
623 entry->next = rememberStack;
624 entry->info = *results;
625 rememberStack = entry;
630 if ( logDwarf ) fprintf(stderr, "DW_CFA_remember_state\n");
632 case DW_CFA_restore_state:
633 if ( rememberStack != NULL ) {
634 PrologInfoStackEntry* top = rememberStack;
635 *results = top->info;
636 rememberStack = top->next;
642 if ( logDwarf ) fprintf(stderr, "DW_CFA_restore_state\n");
645 reg = addressSpace.getULEB128(p, instructionsEnd);
646 offset = addressSpace.getULEB128(p, instructionsEnd);
647 if ( reg > kMaxRegisterNumber ) {
648 fprintf(stderr, "malformed DW_CFA_def_cfa dwarf unwind, reg too big\n");
651 results->cfaRegister = reg;
652 results->cfaRegisterOffset = offset;
653 if ( offset > 0x80000000 )
654 results->cfaOffsetWasNegative = true;
655 if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa(reg=%lld, offset=%lld)\n", reg, offset);
657 case DW_CFA_def_cfa_register:
658 reg = addressSpace.getULEB128(p, instructionsEnd);
659 if ( reg > kMaxRegisterNumber ) {
660 fprintf(stderr, "malformed DW_CFA_def_cfa_register dwarf unwind, reg too big\n");
663 results->cfaRegister = reg;
664 if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_register(%lld)\n", reg);
666 case DW_CFA_def_cfa_offset:
667 results->cfaRegisterOffset = addressSpace.getULEB128(p, instructionsEnd);
668 results->codeOffsetAtStackDecrement = codeOffset;
669 if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_offset(%d)\n", results->cfaRegisterOffset);
671 case DW_CFA_def_cfa_expression:
672 results->cfaRegister = 0;
673 results->cfaExpression = p;
674 length = addressSpace.getULEB128(p, instructionsEnd);
676 if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_expression(expression=0x%llX, length=%llu)\n",
677 results->cfaExpression, length);
679 case DW_CFA_expression:
680 reg = addressSpace.getULEB128(p, instructionsEnd);
681 if ( reg > kMaxRegisterNumber ) {
682 fprintf(stderr, "malformed DW_CFA_expression dwarf unwind, reg too big\n");
685 results->savedRegisters[reg].location = kRegisterAtExpression;
686 results->savedRegisters[reg].value = p;
687 length = addressSpace.getULEB128(p, instructionsEnd);
689 if ( logDwarf ) fprintf(stderr, "DW_CFA_expression(reg=%lld, expression=0x%llX, length=%llu)\n",
690 reg, results->savedRegisters[reg].value, length);
692 case DW_CFA_offset_extended_sf:
693 reg = addressSpace.getULEB128(p, instructionsEnd);
694 if ( reg > kMaxRegisterNumber ) {
695 fprintf(stderr, "malformed DW_CFA_offset_extended_sf dwarf unwind, reg too big\n");
698 offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
699 if ( results->savedRegisters[reg].location != kRegisterUnused )
700 results->registerSavedMoreThanOnce = true;
701 results->savedRegisters[reg].location = kRegisterInCFA;
702 results->savedRegisters[reg].value = offset;
703 if ( logDwarf ) fprintf(stderr, "DW_CFA_offset_extended_sf(reg=%lld, offset=%lld)\n", reg, offset);
705 case DW_CFA_def_cfa_sf:
706 reg = addressSpace.getULEB128(p, instructionsEnd);
707 offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
708 if ( reg > kMaxRegisterNumber ) {
709 fprintf(stderr, "malformed DW_CFA_def_cfa_sf dwarf unwind, reg too big\n");
712 results->cfaRegister = reg;
713 results->cfaRegisterOffset = offset;
714 if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_sf(reg=%lld, offset=%lld)\n", reg, offset);
716 case DW_CFA_def_cfa_offset_sf:
717 results->cfaRegisterOffset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
718 results->codeOffsetAtStackDecrement = codeOffset;
719 if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_offset_sf(%d)\n", results->cfaRegisterOffset);
721 case DW_CFA_val_offset:
722 reg = addressSpace.getULEB128(p, instructionsEnd);
723 offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
724 results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
725 results->savedRegisters[reg].value = offset;
726 if ( logDwarf ) fprintf(stderr, "DW_CFA_val_offset(reg=%lld, offset=%lld\n", reg, offset);
728 case DW_CFA_val_offset_sf:
729 reg = addressSpace.getULEB128(p, instructionsEnd);
730 if ( reg > kMaxRegisterNumber ) {
731 fprintf(stderr, "malformed DW_CFA_val_offset_sf dwarf unwind, reg too big\n");
734 offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
735 results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
736 results->savedRegisters[reg].value = offset;
737 if ( logDwarf ) fprintf(stderr, "DW_CFA_val_offset_sf(reg=%lld, offset=%lld\n", reg, offset);
739 case DW_CFA_val_expression:
740 reg = addressSpace.getULEB128(p, instructionsEnd);
741 if ( reg > kMaxRegisterNumber ) {
742 fprintf(stderr, "malformed DW_CFA_val_expression dwarf unwind, reg too big\n");
745 results->savedRegisters[reg].location = kRegisterIsExpression;
746 results->savedRegisters[reg].value = p;
747 length = addressSpace.getULEB128(p, instructionsEnd);
749 if ( logDwarf ) fprintf(stderr, "DW_CFA_val_expression(reg=%lld, expression=0x%llX, length=%lld)\n",
750 reg, results->savedRegisters[reg].value, length);
752 case DW_CFA_GNU_args_size:
753 offset = addressSpace.getULEB128(p, instructionsEnd);
754 results->spExtraArgSize = offset;
755 if ( logDwarf ) fprintf(stderr, "DW_CFA_GNU_args_size(%lld)\n", offset);
757 case DW_CFA_GNU_negative_offset_extended:
758 reg = addressSpace.getULEB128(p, instructionsEnd);
759 if ( reg > kMaxRegisterNumber ) {
760 fprintf(stderr, "malformed DW_CFA_GNU_negative_offset_extended dwarf unwind, reg too big\n");
763 offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
764 if ( results->savedRegisters[reg].location != kRegisterUnused )
765 results->registerSavedMoreThanOnce = true;
766 results->savedRegisters[reg].location = kRegisterInCFA;
767 results->savedRegisters[reg].value = -offset;
768 if ( logDwarf ) fprintf(stderr, "DW_CFA_GNU_negative_offset_extended(%lld)\n", offset);
771 operand = opcode & 0x3F;
772 switch ( opcode & 0xC0 ) {
775 offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
776 if ( results->savedRegisters[reg].location != kRegisterUnused ) {
777 // look for idiom of PC saved twice in CIE to mean disable compact unwind encoding
778 if ( (pcoffset == (pint_t)(-1))
779 && (results->savedRegisters[reg].location == kRegisterInCFA)
780 && (results->savedRegisters[reg].value == offset) )
781 results->registerSavedTwiceInCIE = reg;
783 results->registerSavedMoreThanOnce = true;
785 results->savedRegisters[reg].location = kRegisterInCFA;
786 results->savedRegisters[reg].value = offset;
787 if ( logDwarf ) fprintf(stderr, "DW_CFA_offset(reg=%d, offset=%lld)\n", operand, offset);
789 case DW_CFA_advance_loc:
790 codeOffset += operand * cieInfo.codeAlignFactor;
791 if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc: new offset=%u\n", codeOffset);
794 // <rdar://problem/7503075> Python crashes when handling an exception thrown by an obj-c object
795 // libffi uses DW_CFA_restore in the middle of some custom dwarf, so it is not a good epilog flag
796 //return true; // gcc-4.5 starts the epilog with this
798 results->savedRegisters[reg] = initialState.savedRegisters[reg];
799 if ( logDwarf ) fprintf(stderr, "DW_CFA_restore(reg=%lld)\n", reg);
802 if ( logDwarf ) fprintf(stderr, "unknown CFA opcode 0x%02X\n", opcode);
812 } // namespace libunwind
815 #endif // __DWARF_PARSER_HPP__