1 //===--------------------------- DwarfParser.hpp --------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is dual licensed under the MIT and the University of Illinois Open 6 // Source Licenses. See LICENSE.TXT for details. 7 // 8 // 9 // Parses DWARF CFIs (FDEs and CIEs). 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef __DWARF_PARSER_HPP__ 14 #define __DWARF_PARSER_HPP__ 15 16 #include <inttypes.h> 17 #include <stdint.h> 18 #include <stdio.h> 19 #include <stdlib.h> 20 21 #include "libunwind.h" 22 #include "dwarf2.h" 23 24 #include "AddressSpace.hpp" 25 26 namespace libunwind { 27 28 /// CFI_Parser does basic parsing of a CFI (Call Frame Information) records. 29 /// See DWARF Spec for details: 30 /// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html 31 /// 32 template <typename A> 33 class CFI_Parser { 34 public: 35 typedef typename A::pint_t pint_t; 36 37 /// Information encoded in a CIE (Common Information Entry) 38 struct CIE_Info { 39 pint_t cieStart; 40 pint_t cieLength; 41 pint_t cieInstructions; 42 uint8_t pointerEncoding; 43 uint8_t lsdaEncoding; 44 uint8_t personalityEncoding; 45 uint8_t personalityOffsetInCIE; 46 pint_t personality; 47 uint32_t codeAlignFactor; 48 int dataAlignFactor; 49 bool isSignalFrame; 50 bool fdesHaveAugmentationData; 51 uint8_t returnAddressRegister; 52 }; 53 54 /// Information about an FDE (Frame Description Entry) 55 struct FDE_Info { 56 pint_t fdeStart; 57 pint_t fdeLength; 58 pint_t fdeInstructions; 59 pint_t pcStart; 60 pint_t pcEnd; 61 pint_t lsda; 62 }; 63 64 enum { 65 kMaxRegisterNumber = _LIBUNWIND_HIGHEST_DWARF_REGISTER 66 }; 67 enum RegisterSavedWhere { 68 kRegisterUnused, 69 kRegisterInCFA, 70 kRegisterOffsetFromCFA, 71 kRegisterInRegister, 72 kRegisterAtExpression, 73 kRegisterIsExpression 74 }; 75 struct RegisterLocation { 76 RegisterSavedWhere location; 77 int64_t value; 78 }; 79 /// Information about a frame layout and registers saved determined 80 /// by "running" the DWARF FDE "instructions" 81 struct PrologInfo { 82 uint32_t cfaRegister; 83 int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset 84 int64_t cfaExpression; // CFA = expression 85 uint32_t spExtraArgSize; 86 uint32_t codeOffsetAtStackDecrement; 87 bool registersInOtherRegisters; 88 bool sameValueUsed; 89 RegisterLocation savedRegisters[kMaxRegisterNumber]; 90 }; 91 92 struct PrologInfoStackEntry { 93 PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i) 94 : next(n), info(i) {} 95 PrologInfoStackEntry *next; 96 PrologInfo info; 97 }; 98 99 static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, 100 uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo, 101 CIE_Info *cieInfo); 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); 107 108 static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo); 109 110 private: 111 static bool parseInstructions(A &addressSpace, pint_t instructions, 112 pint_t instructionsEnd, const CIE_Info &cieInfo, 113 pint_t pcoffset, 114 PrologInfoStackEntry *&rememberStack, 115 PrologInfo *results); 116 }; 117 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) { 122 pint_t p = fdeStart; 123 pint_t cfiLength = (pint_t)addressSpace.get32(p); 124 p += 4; 125 if (cfiLength == 0xffffffff) { 126 // 0xffffffff means length is really next 8 bytes 127 cfiLength = (pint_t)addressSpace.get64(p); 128 p += 8; 129 } 130 if (cfiLength == 0) 131 return "FDE has zero length"; // end marker 132 uint32_t ciePointer = addressSpace.get32(p); 133 if (ciePointer == 0) 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); 138 if (err != NULL) 139 return err; 140 p += 4; 141 // Parse pc begin and range. 142 pint_t pcStart = 143 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding); 144 pint_t pcRange = 145 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F); 146 // Parse rest of info. 147 fdeInfo->lsda = 0; 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) != 156 0) { 157 // Reset pointer and re-parse LSDA address. 158 p = lsdaStart; 159 fdeInfo->lsda = 160 addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); 161 } 162 } 163 p = endOfAug; 164 } 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 171 } 172 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); 185 p += 4; 186 if (cfiLength == 0xffffffff) { 187 // 0xffffffff means length is really next 8 bytes 188 cfiLength = (pint_t)addressSpace.get64(p); 189 p += 8; 190 } 191 if (cfiLength == 0) 192 return false; // end marker 193 uint32_t id = addressSpace.get32(p); 194 if (id == 0) { 195 // Skip over CIEs. 196 p += cfiLength; 197 } else { 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) { 205 p += 4; 206 // Parse pc begin and range. 207 pint_t pcStart = 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 214 fdeInfo->lsda = 0; 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. 225 p = lsdaStart; 226 fdeInfo->lsda = addressSpace 227 .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); 228 } 229 } 230 p = endOfAug; 231 } 232 fdeInfo->fdeStart = currentCFI; 233 fdeInfo->fdeLength = nextCFI - currentCFI; 234 fdeInfo->fdeInstructions = p; 235 fdeInfo->pcStart = pcStart; 236 fdeInfo->pcEnd = pcStart + pcRange; 237 return true; 238 } else { 239 // pc is not in begin/range, skip this FDE 240 } 241 } else { 242 // Malformed CIE, now augmentation describing pc range encoding. 243 } 244 } else { 245 // malformed FDE. CIE is bad 246 } 247 p = nextCFI; 248 } 249 } 250 return false; 251 } 252 253 /// Extract info from a CIE 254 template <typename A> 255 const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie, 256 CIE_Info *cieInfo) { 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; 267 pint_t p = cie; 268 pint_t cieLength = (pint_t)addressSpace.get32(p); 269 p += 4; 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); 274 p += 8; 275 cieContentEnd = p + cieLength; 276 } 277 if (cieLength == 0) 278 return NULL; 279 // CIE ID is always 0 280 if (addressSpace.get32(p) != 0) 281 return "CIE ID is not zero"; 282 p += 4; 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"; 287 ++p; 288 // save start of augmentation string and find end 289 pint_t strStart = p; 290 while (addressSpace.get8(p) != 0) 291 ++p; 292 ++p; 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)) { 308 case 'z': 309 cieInfo->fdesHaveAugmentationData = true; 310 break; 311 case 'P': 312 cieInfo->personalityEncoding = addressSpace.get8(p); 313 ++p; 314 cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie); 315 cieInfo->personality = addressSpace 316 .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding); 317 break; 318 case 'L': 319 cieInfo->lsdaEncoding = addressSpace.get8(p); 320 ++p; 321 break; 322 case 'R': 323 cieInfo->pointerEncoding = addressSpace.get8(p); 324 ++p; 325 break; 326 case 'S': 327 cieInfo->isSignalFrame = true; 328 break; 329 default: 330 // ignore unknown letters 331 break; 332 } 333 } 334 } 335 cieInfo->cieLength = cieContentEnd - cieInfo->cieStart; 336 cieInfo->cieInstructions = p; 337 return result; 338 } 339 340 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) { 347 // clear results 348 memset(results, '\0', sizeof(PrologInfo)); 349 PrologInfoStackEntry *rememberStack = NULL; 350 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); 358 } 359 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; 371 if (logDwarf) 372 fprintf(stderr, "parseInstructions(instructions=0x%0" PRIx64 ")\n", 373 (uint64_t)instructionsEnd); 374 375 // see DWARF Spec, section 6.4.2 for details on unwind opcodes 376 while ((p < instructionsEnd) && (codeOffset < pcoffset)) { 377 uint64_t reg; 378 uint64_t reg2; 379 int64_t offset; 380 uint64_t length; 381 uint8_t opcode = addressSpace.get8(p); 382 uint8_t operand; 383 #if !defined(_LIBUNWIND_NO_HEAP) 384 PrologInfoStackEntry *entry; 385 #endif 386 ++p; 387 switch (opcode) { 388 case DW_CFA_nop: 389 if (logDwarf) 390 fprintf(stderr, "DW_CFA_nop\n"); 391 break; 392 case DW_CFA_set_loc: 393 codeOffset = 394 addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding); 395 if (logDwarf) 396 fprintf(stderr, "DW_CFA_set_loc\n"); 397 break; 398 case DW_CFA_advance_loc1: 399 codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor); 400 p += 1; 401 if (logDwarf) 402 fprintf(stderr, "DW_CFA_advance_loc1: new offset=%" PRIu64 "\n", 403 (uint64_t)codeOffset); 404 break; 405 case DW_CFA_advance_loc2: 406 codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor); 407 p += 2; 408 if (logDwarf) 409 fprintf(stderr, "DW_CFA_advance_loc2: new offset=%" PRIu64 "\n", 410 (uint64_t)codeOffset); 411 break; 412 case DW_CFA_advance_loc4: 413 codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor); 414 p += 4; 415 if (logDwarf) 416 fprintf(stderr, "DW_CFA_advance_loc4: new offset=%" PRIu64 "\n", 417 (uint64_t)codeOffset); 418 break; 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) { 424 fprintf(stderr, 425 "malformed DW_CFA_offset_extended DWARF unwind, reg too big\n"); 426 return false; 427 } 428 results->savedRegisters[reg].location = kRegisterInCFA; 429 results->savedRegisters[reg].value = offset; 430 if (logDwarf) 431 fprintf(stderr, 432 "DW_CFA_offset_extended(reg=%" PRIu64 ", offset=%" PRId64 ")\n", 433 reg, offset); 434 break; 435 case DW_CFA_restore_extended: 436 reg = addressSpace.getULEB128(p, instructionsEnd); 437 ; 438 if (reg > kMaxRegisterNumber) { 439 fprintf( 440 stderr, 441 "malformed DW_CFA_restore_extended DWARF unwind, reg too big\n"); 442 return false; 443 } 444 results->savedRegisters[reg] = initialState.savedRegisters[reg]; 445 if (logDwarf) 446 fprintf(stderr, "DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg); 447 break; 448 case DW_CFA_undefined: 449 reg = addressSpace.getULEB128(p, instructionsEnd); 450 if (reg > kMaxRegisterNumber) { 451 fprintf(stderr, 452 "malformed DW_CFA_undefined DWARF unwind, reg too big\n"); 453 return false; 454 } 455 results->savedRegisters[reg].location = kRegisterUnused; 456 if (logDwarf) 457 fprintf(stderr, "DW_CFA_undefined(reg=%" PRIu64 ")\n", reg); 458 break; 459 case DW_CFA_same_value: 460 reg = addressSpace.getULEB128(p, instructionsEnd); 461 if (reg > kMaxRegisterNumber) { 462 fprintf(stderr, 463 "malformed DW_CFA_same_value DWARF unwind, reg too big\n"); 464 return false; 465 } 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; 473 if (logDwarf) 474 fprintf(stderr, "DW_CFA_same_value(reg=%" PRIu64 ")\n", reg); 475 break; 476 case DW_CFA_register: 477 reg = addressSpace.getULEB128(p, instructionsEnd); 478 reg2 = addressSpace.getULEB128(p, instructionsEnd); 479 if (reg > kMaxRegisterNumber) { 480 fprintf(stderr, 481 "malformed DW_CFA_register DWARF unwind, reg too big\n"); 482 return false; 483 } 484 if (reg2 > kMaxRegisterNumber) { 485 fprintf(stderr, 486 "malformed DW_CFA_register DWARF unwind, reg2 too big\n"); 487 return false; 488 } 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 if (logDwarf) 494 fprintf(stderr, "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", 495 reg, reg2); 496 break; 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)); 501 if (entry != NULL) { 502 entry->next = rememberStack; 503 entry->info = *results; 504 rememberStack = entry; 505 } else { 506 return false; 507 } 508 if (logDwarf) 509 fprintf(stderr, "DW_CFA_remember_state\n"); 510 break; 511 case DW_CFA_restore_state: 512 if (rememberStack != NULL) { 513 PrologInfoStackEntry *top = rememberStack; 514 *results = top->info; 515 rememberStack = top->next; 516 free((char *)top); 517 } else { 518 return false; 519 } 520 if (logDwarf) 521 fprintf(stderr, "DW_CFA_restore_state\n"); 522 break; 523 #endif 524 case DW_CFA_def_cfa: 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"); 529 return false; 530 } 531 results->cfaRegister = (uint32_t)reg; 532 results->cfaRegisterOffset = (int32_t)offset; 533 if (logDwarf) 534 fprintf(stderr, "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", 535 reg, offset); 536 break; 537 case DW_CFA_def_cfa_register: 538 reg = addressSpace.getULEB128(p, instructionsEnd); 539 if (reg > kMaxRegisterNumber) { 540 fprintf( 541 stderr, 542 "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big\n"); 543 return false; 544 } 545 results->cfaRegister = (uint32_t)reg; 546 if (logDwarf) 547 fprintf(stderr, "DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg); 548 break; 549 case DW_CFA_def_cfa_offset: 550 results->cfaRegisterOffset = (int32_t) 551 addressSpace.getULEB128(p, instructionsEnd); 552 results->codeOffsetAtStackDecrement = (uint32_t)codeOffset; 553 if (logDwarf) 554 fprintf(stderr, "DW_CFA_def_cfa_offset(%d)\n", 555 results->cfaRegisterOffset); 556 break; 557 case DW_CFA_def_cfa_expression: 558 results->cfaRegister = 0; 559 results->cfaExpression = (int64_t)p; 560 length = addressSpace.getULEB128(p, instructionsEnd); 561 p += length; 562 if (logDwarf) 563 fprintf(stderr, "DW_CFA_def_cfa_expression(expression=0x%" PRIx64 564 ", length=%" PRIu64 ")\n", 565 results->cfaExpression, length); 566 break; 567 case DW_CFA_expression: 568 reg = addressSpace.getULEB128(p, instructionsEnd); 569 if (reg > kMaxRegisterNumber) { 570 fprintf(stderr, 571 "malformed DW_CFA_expression DWARF unwind, reg too big\n"); 572 return false; 573 } 574 results->savedRegisters[reg].location = kRegisterAtExpression; 575 results->savedRegisters[reg].value = (int64_t)p; 576 length = addressSpace.getULEB128(p, instructionsEnd); 577 p += length; 578 if (logDwarf) 579 fprintf(stderr, "DW_CFA_expression(reg=%" PRIu64 580 ", expression=0x%" PRIx64 ", length=%" PRIu64 ")\n", 581 reg, results->savedRegisters[reg].value, length); 582 break; 583 case DW_CFA_offset_extended_sf: 584 reg = addressSpace.getULEB128(p, instructionsEnd); 585 if (reg > kMaxRegisterNumber) { 586 fprintf( 587 stderr, 588 "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big\n"); 589 return false; 590 } 591 offset = 592 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; 593 results->savedRegisters[reg].location = kRegisterInCFA; 594 results->savedRegisters[reg].value = offset; 595 if (logDwarf) 596 fprintf(stderr, "DW_CFA_offset_extended_sf(reg=%" PRIu64 597 ", offset=%" PRId64 ")\n", 598 reg, offset); 599 break; 600 case DW_CFA_def_cfa_sf: 601 reg = addressSpace.getULEB128(p, instructionsEnd); 602 offset = 603 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; 604 if (reg > kMaxRegisterNumber) { 605 fprintf(stderr, 606 "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big\n"); 607 return false; 608 } 609 results->cfaRegister = (uint32_t)reg; 610 results->cfaRegisterOffset = (int32_t)offset; 611 if (logDwarf) 612 fprintf(stderr, 613 "DW_CFA_def_cfa_sf(reg=%" PRIu64 ", offset=%" PRId64 ")\n", reg, 614 offset); 615 break; 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; 620 if (logDwarf) 621 fprintf(stderr, "DW_CFA_def_cfa_offset_sf(%d)\n", 622 results->cfaRegisterOffset); 623 break; 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; 630 if (logDwarf) 631 fprintf(stderr, 632 "DW_CFA_val_offset(reg=%" PRIu64 ", offset=%" PRId64 "\n", reg, 633 offset); 634 break; 635 case DW_CFA_val_offset_sf: 636 reg = addressSpace.getULEB128(p, instructionsEnd); 637 if (reg > kMaxRegisterNumber) { 638 fprintf(stderr, 639 "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big\n"); 640 return false; 641 } 642 offset = 643 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; 644 results->savedRegisters[reg].location = kRegisterOffsetFromCFA; 645 results->savedRegisters[reg].value = offset; 646 if (logDwarf) 647 fprintf(stderr, 648 "DW_CFA_val_offset_sf(reg=%" PRIu64 ", offset=%" PRId64 "\n", 649 reg, offset); 650 break; 651 case DW_CFA_val_expression: 652 reg = addressSpace.getULEB128(p, instructionsEnd); 653 if (reg > kMaxRegisterNumber) { 654 fprintf(stderr, 655 "malformed DW_CFA_val_expression DWARF unwind, reg too big\n"); 656 return false; 657 } 658 results->savedRegisters[reg].location = kRegisterIsExpression; 659 results->savedRegisters[reg].value = (int64_t)p; 660 length = addressSpace.getULEB128(p, instructionsEnd); 661 p += length; 662 if (logDwarf) 663 fprintf(stderr, "DW_CFA_val_expression(reg=%" PRIu64 664 ", expression=0x%" PRIx64 ", length=%" PRIu64 ")\n", 665 reg, results->savedRegisters[reg].value, length); 666 break; 667 case DW_CFA_GNU_args_size: 668 length = addressSpace.getULEB128(p, instructionsEnd); 669 results->spExtraArgSize = (uint32_t)length; 670 if (logDwarf) 671 fprintf(stderr, "DW_CFA_GNU_args_size(%" PRIu64 ")\n", length); 672 break; 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"); 678 return false; 679 } 680 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) 681 * cieInfo.dataAlignFactor; 682 results->savedRegisters[reg].location = kRegisterInCFA; 683 results->savedRegisters[reg].value = -offset; 684 if (logDwarf) 685 fprintf(stderr, "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", 686 offset); 687 break; 688 default: 689 operand = opcode & 0x3F; 690 switch (opcode & 0xC0) { 691 case DW_CFA_offset: 692 reg = operand; 693 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) 694 * cieInfo.dataAlignFactor; 695 results->savedRegisters[reg].location = kRegisterInCFA; 696 results->savedRegisters[reg].value = offset; 697 if (logDwarf) 698 fprintf(stderr, "DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n", 699 operand, offset); 700 break; 701 case DW_CFA_advance_loc: 702 codeOffset += operand * cieInfo.codeAlignFactor; 703 if (logDwarf) 704 fprintf(stderr, "DW_CFA_advance_loc: new offset=%" PRIu64 "\n", 705 (uint64_t)codeOffset); 706 break; 707 case DW_CFA_restore: 708 reg = operand; 709 results->savedRegisters[reg] = initialState.savedRegisters[reg]; 710 if (logDwarf) 711 fprintf(stderr, "DW_CFA_restore(reg=%" PRIu64 ")\n", reg); 712 break; 713 default: 714 if (logDwarf) 715 fprintf(stderr, "unknown CFA opcode 0x%02X\n", opcode); 716 return false; 717 } 718 } 719 } 720 721 return true; 722 } 723 724 } // namespace libunwind 725 726 #endif // __DWARF_PARSER_HPP__ 727