1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 2 * 3 * Copyright (c) 2008-2010 Apple Inc. All rights reserved. 4 * 5 * @APPLE_LICENSE_HEADER_START@ 6 * 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 12 * file. 13 * 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. 21 * 22 * @APPLE_LICENSE_HEADER_END@ 23 */ 24 25// 26// processor specific parsing of dwarf unwind instructions 27// 28 29#ifndef __DWARF_PARSER_HPP__ 30#define __DWARF_PARSER_HPP__ 31 32#include <stdint.h> 33#include <stdio.h> 34#include <stdlib.h> 35 36#include <vector> 37 38#include "libunwind.h" 39#include "dwarf2.h" 40 41#include "AddressSpace.hpp" 42 43 44namespace libunwind { 45 46 47/// 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 51/// 52template <typename A> 53class CFI_Parser 54{ 55public: 56 typedef typename A::pint_t pint_t; 57 58 /// 59 /// Information encoded in a CIE (Common Information Entry) 60 /// 61 struct CIE_Info { 62 pint_t cieStart; 63 pint_t cieLength; 64 pint_t cieInstructions; 65 uint8_t pointerEncoding; 66 uint8_t lsdaEncoding; 67 uint8_t personalityEncoding; 68 uint8_t personalityOffsetInCIE; 69 pint_t personality; 70 int codeAlignFactor; 71 int dataAlignFactor; 72 bool isSignalFrame; 73 bool fdesHaveAugmentationData; 74 }; 75 76 /// 77 /// Information about an FDE (Frame Description Entry) 78 /// 79 struct FDE_Info { 80 pint_t fdeStart; 81 pint_t fdeLength; 82 pint_t fdeInstructions; 83 pint_t pcStart; 84 pint_t pcEnd; 85 pint_t lsda; 86 }; 87 88 /// 89 /// Used by linker when parsing __eh_frame section 90 /// 91 struct FDE_Reference { 92 pint_t address; 93 uint32_t offsetInFDE; 94 uint8_t encodingOfAddress; 95 }; 96 struct FDE_Atom_Info { 97 pint_t fdeAddress; 98 FDE_Reference function; 99 FDE_Reference cie; 100 FDE_Reference lsda; 101 }; 102 struct CIE_Atom_Info { 103 pint_t cieAddress; 104 FDE_Reference personality; 105 }; 106 107 108 /// 109 /// Information about a frame layout and registers saved determined 110 /// by "running" the dwarf FDE "instructions" 111 /// 112 enum { kMaxRegisterNumber = 120 }; 113 enum RegisterSavedWhere { kRegisterUnused, kRegisterInCFA, kRegisterOffsetFromCFA, 114 kRegisterInRegister, kRegisterAtExpression, kRegisterIsExpression } ; 115 struct RegisterLocation { 116 RegisterSavedWhere location; 117 int64_t value; 118 }; 119 struct PrologInfo { 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; 129 bool sameValueUsed; 130 RegisterLocation savedRegisters[kMaxRegisterNumber]; // from where to restore registers 131 }; 132 133 struct PrologInfoStackEntry { 134 PrologInfoStackEntry(PrologInfoStackEntry* n, const PrologInfo& i) 135 : next(n), info(i) {} 136 PrologInfoStackEntry* next; 137 PrologInfo info; 138 }; 139 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); 146 147 static const char* parseCIE(A& addressSpace, pint_t cie, CIE_Info* cieInfo); 148 149private: 150 static bool parseInstructions(A& addressSpace, pint_t instructions, pint_t instructionsEnd, const CIE_Info& cieInfo, 151 pint_t pcoffset, PrologInfoStackEntry*& rememberStack, PrologInfo* results); 152}; 153 154 155/// 156/// Parse a FDE into a CIE_Info and an FDE_Info 157/// 158template <typename A> 159const char* CFI_Parser<A>::decodeFDE(A& addressSpace, pint_t fdeStart, FDE_Info* fdeInfo, CIE_Info* cieInfo) 160{ 161 pint_t p = fdeStart; 162 uint64_t cfiLength = addressSpace.get32(p); 163 p += 4; 164 if ( cfiLength == 0xffffffff ) { 165 // 0xffffffff means length is really next 8 bytes 166 cfiLength = addressSpace.get64(p); 167 p += 8; 168 } 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); 177 if (err != NULL) 178 return err; 179 p += 4; 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 184 fdeInfo->lsda = 0; 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 194 p = lsdaStart; 195 fdeInfo->lsda = addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); 196 } 197 } 198 p = endOfAug; 199 } 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 206} 207 208 209/// 210/// Scan an eh_frame section to find an FDE for a pc 211/// 212template <typename A> 213bool CFI_Parser<A>::findFDE(A& addressSpace, pint_t pc, pint_t ehSectionStart, uint32_t sectionLength, pint_t fdeHint, FDE_Info* fdeInfo, CIE_Info* cieInfo) 214{ 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); 222 p += 4; 223 if ( cfiLength == 0xffffffff ) { 224 // 0xffffffff means length is really next 8 bytes 225 cfiLength = addressSpace.get64(p); 226 p += 8; 227 } 228 if ( cfiLength == 0 ) 229 return false; // end marker 230 uint32_t id = addressSpace.get32(p); 231 if ( id == 0 ) { 232 // skip over CIEs 233 p += cfiLength; 234 } 235 else { 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 ) { 243 p += 4; 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 251 fdeInfo->lsda = 0; 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 261 p = lsdaStart; 262 fdeInfo->lsda = addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); 263 } 264 } 265 p = endOfAug; 266 } 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)); 273 return true; 274 } 275 else { 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 278 } 279 } 280 else { 281 // malformed CIE, now augmentation describing pc range encoding 282 //fprintf(stderr, "malformed CIE\n"); 283 } 284 } 285 else { 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); 289 } 290 p = nextCFI; 291 } 292 } 293 //fprintf(stderr, "findFDE(pc=0x%llX) not found\n",(uint64_t)pc); 294 return false; 295} 296 297 298 299/// 300/// Extract info from a CIE 301/// 302template <typename A> 303const char* CFI_Parser<A>::parseCIE(A& addressSpace, pint_t cie, CIE_Info* cieInfo) 304{ 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; 316 pint_t p = cie; 317 uint64_t cieLength = addressSpace.get32(p); 318 p += 4; 319 pint_t cieContentEnd = p + cieLength; 320 if ( cieLength == 0xffffffff ) { 321 // 0xffffffff means length is really next 8 bytes 322 cieLength = addressSpace.get64(p); 323 p += 8; 324 cieContentEnd = p + cieLength; 325 } 326 if ( cieLength == 0 ) 327 return NULL; 328 // CIE ID is always 0 329 if ( addressSpace.get32(p) != 0 ) 330 return "CIE ID is not zero"; 331 p += 4; 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"; 336 ++p; 337 // save start of augmentation string and find end 338 pint_t strStart = p; 339 while ( addressSpace.get8(p) != 0 ) 340 ++p; 341 ++p; 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) ) { 355 case 'z': 356 cieInfo->fdesHaveAugmentationData = true; 357 break; 358 case 'P': 359 cieInfo->personalityEncoding = addressSpace.get8(p); 360 ++p; 361 cieInfo->personalityOffsetInCIE = p-cie; 362 cieInfo->personality = addressSpace.getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding); 363 break; 364 case 'L': 365 cieInfo->lsdaEncoding = addressSpace.get8(p); 366 ++p; 367 break; 368 case 'R': 369 cieInfo->pointerEncoding = addressSpace.get8(p); 370 ++p; 371 break; 372 case 'S': 373 cieInfo->isSignalFrame = true; 374 break; 375 default: 376 // ignore unknown letters 377 break; 378 } 379 } 380 } 381 cieInfo->cieLength = cieContentEnd - cieInfo->cieStart; 382 cieInfo->cieInstructions = p; 383 return result; 384} 385 386 387template <typename A> 388uint32_t CFI_Parser<A>::getCFICount(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength) 389{ 390 uint32_t count = 0; 391 const pint_t ehSectionEnd = ehSectionStart + sectionLength; 392 for (pint_t p=ehSectionStart; p < ehSectionEnd; ) { 393 uint64_t cfiLength = addressSpace.get32(p); 394 p += 4; 395 if ( cfiLength == 0xffffffff ) { 396 // 0xffffffff means length is really next 8 bytes 397 cfiLength = addressSpace.get64(p); 398 p += 8; 399 } 400 if ( cfiLength == 0 ) 401 return count; // end marker 402 ++count; 403 p += cfiLength; 404 } 405 return count; 406} 407 408 409 410template <typename A> 411const 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) 413{ 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); 418 p += 4; 419 if ( cfiLength == 0xffffffff ) { 420 // 0xffffffff means length is really next 8 bytes 421 cfiLength = addressSpace.get64(p); 422 p += 8; 423 } 424 if ( cfiLength == 0 ) 425 return NULL; // end marker 426 uint32_t id = addressSpace.get32(p); 427 if ( id == 0 ) { 428 // is CIE 429 CIE_Info cieInfo; 430 const char* err = parseCIE(addressSpace, currentCFI, &cieInfo); 431 if ( err != NULL ) 432 return err; 433 CIE_Atom_Info entry; 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); 439 p += cfiLength; 440 } 441 else { 442 // is FDE 443 FDE_Atom_Info 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"; 454 CIE_Info cieInfo; 455 const char* err = parseCIE(addressSpace, cieStart, &cieInfo); 456 if ( err != NULL ) 457 return err; 458 entry.cie.address = cieStart; 459 entry.cie.offsetInFDE = p-currentCFI; 460 entry.cie.encodingOfAddress = DW_EH_PE_sdata4 | DW_EH_PE_pcrel; 461 p += 4; 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; 480 } 481 p = endOfAug; 482 } 483 fdes.push_back(entry); 484 p = nextCFI; 485 } 486 } 487 return NULL; // success 488} 489 490 491 492/// 493/// "run" the dwarf instructions and create the abstact PrologInfo for an FDE 494/// 495template <typename A> 496bool CFI_Parser<A>::parseFDEInstructions(A& addressSpace, const FDE_Info& fdeInfo, const CIE_Info& cieInfo, pint_t upToPC, PrologInfo* results) 497{ 498 // clear results 499 bzero(results, sizeof(PrologInfo)); 500 PrologInfoStackEntry* rememberStack = NULL; 501 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); 507} 508 509 510/// 511/// "run" the dwarf instructions 512/// 513template <typename A> 514bool CFI_Parser<A>::parseInstructions(A& addressSpace, pint_t instructions, pint_t instructionsEnd, const CIE_Info& cieInfo, 515 pint_t pcoffset, PrologInfoStackEntry*& rememberStack, PrologInfo* results) 516{ 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); 522 523 // see Dwarf Spec, section 6.4.2 for details on unwind opcodes 524 while ( (p < instructionsEnd) && (codeOffset < pcoffset) ) { 525 uint64_t reg; 526 uint64_t reg2; 527 int64_t offset; 528 uint64_t length; 529 uint8_t opcode = addressSpace.get8(p); 530 uint8_t operand; 531 PrologInfoStackEntry* entry; 532 ++p; 533 switch (opcode) { 534 case DW_CFA_nop: 535 if ( logDwarf ) fprintf(stderr, "DW_CFA_nop\n"); 536 break; 537 case DW_CFA_set_loc: 538 codeOffset = addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding); 539 if ( logDwarf ) fprintf(stderr, "DW_CFA_set_loc\n"); 540 break; 541 case DW_CFA_advance_loc1: 542 codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor); 543 p += 1; 544 if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc1: new offset=%u\n", codeOffset); 545 break; 546 case DW_CFA_advance_loc2: 547 codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor); 548 p += 2; 549 if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc2: new offset=%u\n", codeOffset); 550 break; 551 case DW_CFA_advance_loc4: 552 codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor); 553 p += 4; 554 if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc4: new offset=%u\n", codeOffset); 555 break; 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"); 561 return false; 562 } 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); 568 break; 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"); 573 return false; 574 } 575 results->savedRegisters[reg] = initialState.savedRegisters[reg]; 576 if ( logDwarf ) fprintf(stderr, "DW_CFA_restore_extended(reg=%lld)\n", reg); 577 break; 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"); 582 return false; 583 } 584 results->savedRegisters[reg].location = kRegisterUnused; 585 if ( logDwarf ) fprintf(stderr, "DW_CFA_undefined(reg=%lld)\n", reg); 586 break; 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"); 591 return false; 592 } 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); 601 break; 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"); 607 return false; 608 } 609 if ( reg2 > kMaxRegisterNumber ) { 610 fprintf(stderr, "malformed DW_CFA_register dwarf unwind, reg2 too big\n"); 611 return false; 612 } 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); 618 break; 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; 626 } 627 else { 628 return false; 629 } 630 if ( logDwarf ) fprintf(stderr, "DW_CFA_remember_state\n"); 631 break; 632 case DW_CFA_restore_state: 633 if ( rememberStack != NULL ) { 634 PrologInfoStackEntry* top = rememberStack; 635 *results = top->info; 636 rememberStack = top->next; 637 free((char*)top); 638 } 639 else { 640 return false; 641 } 642 if ( logDwarf ) fprintf(stderr, "DW_CFA_restore_state\n"); 643 break; 644 case DW_CFA_def_cfa: 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"); 649 return false; 650 } 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); 656 break; 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"); 661 return false; 662 } 663 results->cfaRegister = reg; 664 if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_register(%lld)\n", reg); 665 break; 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); 670 break; 671 case DW_CFA_def_cfa_expression: 672 results->cfaRegister = 0; 673 results->cfaExpression = p; 674 length = addressSpace.getULEB128(p, instructionsEnd); 675 p += length; 676 if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_expression(expression=0x%llX, length=%llu)\n", 677 results->cfaExpression, length); 678 break; 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"); 683 return false; 684 } 685 results->savedRegisters[reg].location = kRegisterAtExpression; 686 results->savedRegisters[reg].value = p; 687 length = addressSpace.getULEB128(p, instructionsEnd); 688 p += length; 689 if ( logDwarf ) fprintf(stderr, "DW_CFA_expression(reg=%lld, expression=0x%llX, length=%llu)\n", 690 reg, results->savedRegisters[reg].value, length); 691 break; 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"); 696 return false; 697 } 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); 704 break; 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"); 710 return false; 711 } 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); 715 break; 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); 720 break; 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); 727 break; 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"); 732 return false; 733 } 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); 738 break; 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"); 743 return false; 744 } 745 results->savedRegisters[reg].location = kRegisterIsExpression; 746 results->savedRegisters[reg].value = p; 747 length = addressSpace.getULEB128(p, instructionsEnd); 748 p += length; 749 if ( logDwarf ) fprintf(stderr, "DW_CFA_val_expression(reg=%lld, expression=0x%llX, length=%lld)\n", 750 reg, results->savedRegisters[reg].value, length); 751 break; 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); 756 break; 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"); 761 return false; 762 } 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); 769 break; 770 default: 771 operand = opcode & 0x3F; 772 switch ( opcode & 0xC0 ) { 773 case DW_CFA_offset: 774 reg = operand; 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; 782 else 783 results->registerSavedMoreThanOnce = true; 784 } 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); 788 break; 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); 792 break; 793 case DW_CFA_restore: 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 797 reg = operand; 798 results->savedRegisters[reg] = initialState.savedRegisters[reg]; 799 if ( logDwarf ) fprintf(stderr, "DW_CFA_restore(reg=%lld)\n", reg); 800 break; 801 default: 802 if ( logDwarf ) fprintf(stderr, "unknown CFA opcode 0x%02X\n", opcode); 803 return false; 804 } 805 } 806 } 807 808 return true; 809} 810 811 812} // namespace libunwind 813 814 815#endif // __DWARF_PARSER_HPP__ 816 817 818 819 820