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 <vector> 22 23 #include "libunwind.h" 24 #include "dwarf2.h" 25 26 #include "AddressSpace.hpp" 27 28 namespace libunwind { 29 30 /// CFI_Parser does basic parsing of a CFI (Call Frame Information) records. 31 /// See Dwarf Spec for details: 32 /// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html 33 /// 34 template <typename A> 35 class CFI_Parser { 36 public: 37 typedef typename A::pint_t pint_t; 38 39 /// Information encoded in a CIE (Common Information Entry) 40 struct CIE_Info { 41 pint_t cieStart; 42 pint_t cieLength; 43 pint_t cieInstructions; 44 uint8_t pointerEncoding; 45 uint8_t lsdaEncoding; 46 uint8_t personalityEncoding; 47 uint8_t personalityOffsetInCIE; 48 pint_t personality; 49 uint32_t codeAlignFactor; 50 int dataAlignFactor; 51 bool isSignalFrame; 52 bool fdesHaveAugmentationData; 53 uint8_t returnAddressRegister; 54 }; 55 56 /// Information about an FDE (Frame Description Entry) 57 struct FDE_Info { 58 pint_t fdeStart; 59 pint_t fdeLength; 60 pint_t fdeInstructions; 61 pint_t pcStart; 62 pint_t pcEnd; 63 pint_t lsda; 64 }; 65 66 enum { 67 kMaxRegisterNumber = 120 68 }; 69 enum RegisterSavedWhere { 70 kRegisterUnused, 71 kRegisterInCFA, 72 kRegisterOffsetFromCFA, 73 kRegisterInRegister, 74 kRegisterAtExpression, 75 kRegisterIsExpression 76 }; 77 struct RegisterLocation { 78 RegisterSavedWhere location; 79 int64_t value; 80 }; 81 /// Information about a frame layout and registers saved determined 82 /// by "running" the dwarf FDE "instructions" 83 struct PrologInfo { 84 uint32_t cfaRegister; 85 int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset 86 int64_t cfaExpression; // CFA = expression 87 uint32_t spExtraArgSize; 88 uint32_t codeOffsetAtStackDecrement; 89 bool registersInOtherRegisters; 90 bool sameValueUsed; 91 RegisterLocation savedRegisters[kMaxRegisterNumber]; 92 }; 93 94 struct PrologInfoStackEntry { 95 PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i) 96 : next(n), info(i) {} 97 PrologInfoStackEntry *next; 98 PrologInfo info; 99 }; 100 101 static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, 102 uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo, 103 CIE_Info *cieInfo); 104 static const char *decodeFDE(A &addressSpace, pint_t fdeStart, 105 FDE_Info *fdeInfo, CIE_Info *cieInfo); 106 static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo, 107 const CIE_Info &cieInfo, pint_t upToPC, 108 PrologInfo *results); 109 110 static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo); 111 112 private: 113 static bool parseInstructions(A &addressSpace, pint_t instructions, 114 pint_t instructionsEnd, const CIE_Info &cieInfo, 115 pint_t pcoffset, 116 PrologInfoStackEntry *&rememberStack, 117 PrologInfo *results); 118 }; 119 120 /// Parse a FDE into a CIE_Info and an FDE_Info 121 template <typename A> 122 const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart, 123 FDE_Info *fdeInfo, CIE_Info *cieInfo) { 124 pint_t p = fdeStart; 125 pint_t cfiLength = (pint_t)addressSpace.get32(p); 126 p += 4; 127 if (cfiLength == 0xffffffff) { 128 // 0xffffffff means length is really next 8 bytes 129 cfiLength = (pint_t)addressSpace.get64(p); 130 p += 8; 131 } 132 if (cfiLength == 0) 133 return "FDE has zero length"; // end marker 134 uint32_t ciePointer = addressSpace.get32(p); 135 if (ciePointer == 0) 136 return "FDE is really a CIE"; // this is a CIE not an FDE 137 pint_t nextCFI = p + cfiLength; 138 pint_t cieStart = p - ciePointer; 139 const char *err = parseCIE(addressSpace, cieStart, cieInfo); 140 if (err != NULL) 141 return err; 142 p += 4; 143 // parse pc begin and range 144 pint_t pcStart = 145 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding); 146 pint_t pcRange = 147 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F); 148 // parse rest of info 149 fdeInfo->lsda = 0; 150 // check for augmentation length 151 if (cieInfo->fdesHaveAugmentationData) { 152 pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI); 153 pint_t endOfAug = p + augLen; 154 if (cieInfo->lsdaEncoding != DW_EH_PE_omit) { 155 // peek at value (without indirection). Zero means no lsda 156 pint_t lsdaStart = p; 157 if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 158 0) { 159 // reset pointer and re-parse lsda address 160 p = lsdaStart; 161 fdeInfo->lsda = 162 addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); 163 } 164 } 165 p = endOfAug; 166 } 167 fdeInfo->fdeStart = fdeStart; 168 fdeInfo->fdeLength = nextCFI - fdeStart; 169 fdeInfo->fdeInstructions = p; 170 fdeInfo->pcStart = pcStart; 171 fdeInfo->pcEnd = pcStart + pcRange; 172 return NULL; // success 173 } 174 175 /// Scan an eh_frame section to find an FDE for a pc 176 template <typename A> 177 bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, 178 uint32_t sectionLength, pint_t fdeHint, 179 FDE_Info *fdeInfo, CIE_Info *cieInfo) { 180 //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc); 181 pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart; 182 const pint_t ehSectionEnd = p + sectionLength; 183 while (p < ehSectionEnd) { 184 pint_t currentCFI = p; 185 //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p); 186 pint_t cfiLength = addressSpace.get32(p); 187 p += 4; 188 if (cfiLength == 0xffffffff) { 189 // 0xffffffff means length is really next 8 bytes 190 cfiLength = (pint_t)addressSpace.get64(p); 191 p += 8; 192 } 193 if (cfiLength == 0) 194 return false; // end marker 195 uint32_t id = addressSpace.get32(p); 196 if (id == 0) { 197 // skip over CIEs 198 p += cfiLength; 199 } else { 200 // process FDE to see if it covers pc 201 pint_t nextCFI = p + cfiLength; 202 uint32_t ciePointer = addressSpace.get32(p); 203 pint_t cieStart = p - ciePointer; 204 // validate pointer to CIE is within section 205 if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) { 206 if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) { 207 p += 4; 208 // parse pc begin and range 209 pint_t pcStart = 210 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding); 211 pint_t pcRange = addressSpace.getEncodedP( 212 p, nextCFI, cieInfo->pointerEncoding & 0x0F); 213 // test if pc is within the function this FDE covers 214 if ((pcStart < pc) && (pc <= pcStart + pcRange)) { 215 // parse rest of info 216 fdeInfo->lsda = 0; 217 // check for augmentation length 218 if (cieInfo->fdesHaveAugmentationData) { 219 pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI); 220 pint_t endOfAug = p + augLen; 221 if (cieInfo->lsdaEncoding != DW_EH_PE_omit) { 222 // peek at value (without indirection). Zero means no lsda 223 pint_t lsdaStart = p; 224 if (addressSpace.getEncodedP( 225 p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) { 226 // reset pointer and re-parse lsda address 227 p = lsdaStart; 228 fdeInfo->lsda = addressSpace 229 .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); 230 } 231 } 232 p = endOfAug; 233 } 234 fdeInfo->fdeStart = currentCFI; 235 fdeInfo->fdeLength = nextCFI - currentCFI; 236 fdeInfo->fdeInstructions = p; 237 fdeInfo->pcStart = pcStart; 238 fdeInfo->pcEnd = pcStart + pcRange; 239 return true; 240 } else { 241 // pc is not in begin/range, skip this FDE 242 } 243 } else { 244 // malformed CIE, now augmentation describing pc range encoding 245 } 246 } else { 247 // malformed FDE. CIE is bad 248 } 249 p = nextCFI; 250 } 251 } 252 return false; 253 } 254 255 /// Extract info from a CIE 256 template <typename A> 257 const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie, 258 CIE_Info *cieInfo) { 259 cieInfo->pointerEncoding = 0; 260 cieInfo->lsdaEncoding = DW_EH_PE_omit; 261 cieInfo->personalityEncoding = 0; 262 cieInfo->personalityOffsetInCIE = 0; 263 cieInfo->personality = 0; 264 cieInfo->codeAlignFactor = 0; 265 cieInfo->dataAlignFactor = 0; 266 cieInfo->isSignalFrame = false; 267 cieInfo->fdesHaveAugmentationData = false; 268 cieInfo->cieStart = cie; 269 pint_t p = cie; 270 pint_t cieLength = (pint_t)addressSpace.get32(p); 271 p += 4; 272 pint_t cieContentEnd = p + cieLength; 273 if (cieLength == 0xffffffff) { 274 // 0xffffffff means length is really next 8 bytes 275 cieLength = (pint_t)addressSpace.get64(p); 276 p += 8; 277 cieContentEnd = p + cieLength; 278 } 279 if (cieLength == 0) 280 return NULL; 281 // CIE ID is always 0 282 if (addressSpace.get32(p) != 0) 283 return "CIE ID is not zero"; 284 p += 4; 285 // Version is always 1 or 3 286 uint8_t version = addressSpace.get8(p); 287 if ((version != 1) && (version != 3)) 288 return "CIE version is not 1 or 3"; 289 ++p; 290 // save start of augmentation string and find end 291 pint_t strStart = p; 292 while (addressSpace.get8(p) != 0) 293 ++p; 294 ++p; 295 // parse code aligment factor 296 cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd); 297 // parse data alignment factor 298 cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd); 299 // parse return address register 300 uint64_t raReg = addressSpace.getULEB128(p, cieContentEnd); 301 assert(raReg < 255 && "return address register too large"); 302 cieInfo->returnAddressRegister = (uint8_t)raReg; 303 // parse augmentation data based on augmentation string 304 const char *result = NULL; 305 if (addressSpace.get8(strStart) == 'z') { 306 // parse augmentation data length 307 addressSpace.getULEB128(p, cieContentEnd); 308 for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) { 309 switch (addressSpace.get8(s)) { 310 case 'z': 311 cieInfo->fdesHaveAugmentationData = true; 312 break; 313 case 'P': 314 cieInfo->personalityEncoding = addressSpace.get8(p); 315 ++p; 316 cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie); 317 cieInfo->personality = addressSpace 318 .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding); 319 break; 320 case 'L': 321 cieInfo->lsdaEncoding = addressSpace.get8(p); 322 ++p; 323 break; 324 case 'R': 325 cieInfo->pointerEncoding = addressSpace.get8(p); 326 ++p; 327 break; 328 case 'S': 329 cieInfo->isSignalFrame = true; 330 break; 331 default: 332 // ignore unknown letters 333 break; 334 } 335 } 336 } 337 cieInfo->cieLength = cieContentEnd - cieInfo->cieStart; 338 cieInfo->cieInstructions = p; 339 return result; 340 } 341 342 343 /// "run" the dwarf instructions and create the abstact PrologInfo for an FDE 344 template <typename A> 345 bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace, 346 const FDE_Info &fdeInfo, 347 const CIE_Info &cieInfo, pint_t upToPC, 348 PrologInfo *results) { 349 // clear results 350 memset(results, '\0', sizeof(PrologInfo)); 351 PrologInfoStackEntry *rememberStack = NULL; 352 353 // parse CIE then FDE instructions 354 return parseInstructions(addressSpace, cieInfo.cieInstructions, 355 cieInfo.cieStart + cieInfo.cieLength, cieInfo, 356 (pint_t)(-1), rememberStack, results) && 357 parseInstructions(addressSpace, fdeInfo.fdeInstructions, 358 fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo, 359 upToPC - fdeInfo.pcStart, rememberStack, results); 360 } 361 362 /// "run" the dwarf instructions 363 template <typename A> 364 bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions, 365 pint_t instructionsEnd, 366 const CIE_Info &cieInfo, pint_t pcoffset, 367 PrologInfoStackEntry *&rememberStack, 368 PrologInfo *results) { 369 const bool logDwarf = false; 370 pint_t p = instructions; 371 pint_t codeOffset = 0; 372 PrologInfo initialState = *results; 373 if (logDwarf) 374 fprintf(stderr, "parseInstructions(instructions=0x%0" PRIx64 ")\n", 375 (uint64_t)instructionsEnd); 376 377 // see Dwarf Spec, section 6.4.2 for details on unwind opcodes 378 while ((p < instructionsEnd) && (codeOffset < pcoffset)) { 379 uint64_t reg; 380 uint64_t reg2; 381 int64_t offset; 382 uint64_t length; 383 uint8_t opcode = addressSpace.get8(p); 384 uint8_t operand; 385 PrologInfoStackEntry *entry; 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 case DW_CFA_remember_state: 498 // avoid operator new, because that would be an upward dependency 499 entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry)); 500 if (entry != NULL) { 501 entry->next = rememberStack; 502 entry->info = *results; 503 rememberStack = entry; 504 } else { 505 return false; 506 } 507 if (logDwarf) 508 fprintf(stderr, "DW_CFA_remember_state\n"); 509 break; 510 case DW_CFA_restore_state: 511 if (rememberStack != NULL) { 512 PrologInfoStackEntry *top = rememberStack; 513 *results = top->info; 514 rememberStack = top->next; 515 free((char *)top); 516 } else { 517 return false; 518 } 519 if (logDwarf) 520 fprintf(stderr, "DW_CFA_restore_state\n"); 521 break; 522 case DW_CFA_def_cfa: 523 reg = addressSpace.getULEB128(p, instructionsEnd); 524 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd); 525 if (reg > kMaxRegisterNumber) { 526 fprintf(stderr, "malformed DW_CFA_def_cfa dwarf unwind, reg too big\n"); 527 return false; 528 } 529 results->cfaRegister = (uint32_t)reg; 530 results->cfaRegisterOffset = (int32_t)offset; 531 if (logDwarf) 532 fprintf(stderr, "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", 533 reg, offset); 534 break; 535 case DW_CFA_def_cfa_register: 536 reg = addressSpace.getULEB128(p, instructionsEnd); 537 if (reg > kMaxRegisterNumber) { 538 fprintf( 539 stderr, 540 "malformed DW_CFA_def_cfa_register dwarf unwind, reg too big\n"); 541 return false; 542 } 543 results->cfaRegister = (uint32_t)reg; 544 if (logDwarf) 545 fprintf(stderr, "DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg); 546 break; 547 case DW_CFA_def_cfa_offset: 548 results->cfaRegisterOffset = (int32_t) 549 addressSpace.getULEB128(p, instructionsEnd); 550 results->codeOffsetAtStackDecrement = (uint32_t)codeOffset; 551 if (logDwarf) 552 fprintf(stderr, "DW_CFA_def_cfa_offset(%d)\n", 553 results->cfaRegisterOffset); 554 break; 555 case DW_CFA_def_cfa_expression: 556 results->cfaRegister = 0; 557 results->cfaExpression = (int64_t)p; 558 length = addressSpace.getULEB128(p, instructionsEnd); 559 p += length; 560 if (logDwarf) 561 fprintf(stderr, "DW_CFA_def_cfa_expression(expression=0x%" PRIx64 562 ", length=%" PRIu64 ")\n", 563 results->cfaExpression, length); 564 break; 565 case DW_CFA_expression: 566 reg = addressSpace.getULEB128(p, instructionsEnd); 567 if (reg > kMaxRegisterNumber) { 568 fprintf(stderr, 569 "malformed DW_CFA_expression dwarf unwind, reg too big\n"); 570 return false; 571 } 572 results->savedRegisters[reg].location = kRegisterAtExpression; 573 results->savedRegisters[reg].value = (int64_t)p; 574 length = addressSpace.getULEB128(p, instructionsEnd); 575 p += length; 576 if (logDwarf) 577 fprintf(stderr, "DW_CFA_expression(reg=%" PRIu64 578 ", expression=0x%" PRIx64 ", length=%" PRIu64 ")\n", 579 reg, results->savedRegisters[reg].value, length); 580 break; 581 case DW_CFA_offset_extended_sf: 582 reg = addressSpace.getULEB128(p, instructionsEnd); 583 if (reg > kMaxRegisterNumber) { 584 fprintf( 585 stderr, 586 "malformed DW_CFA_offset_extended_sf dwarf unwind, reg too big\n"); 587 return false; 588 } 589 offset = 590 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; 591 results->savedRegisters[reg].location = kRegisterInCFA; 592 results->savedRegisters[reg].value = offset; 593 if (logDwarf) 594 fprintf(stderr, "DW_CFA_offset_extended_sf(reg=%" PRIu64 595 ", offset=%" PRId64 ")\n", 596 reg, offset); 597 break; 598 case DW_CFA_def_cfa_sf: 599 reg = addressSpace.getULEB128(p, instructionsEnd); 600 offset = 601 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; 602 if (reg > kMaxRegisterNumber) { 603 fprintf(stderr, 604 "malformed DW_CFA_def_cfa_sf dwarf unwind, reg too big\n"); 605 return false; 606 } 607 results->cfaRegister = (uint32_t)reg; 608 results->cfaRegisterOffset = (int32_t)offset; 609 if (logDwarf) 610 fprintf(stderr, 611 "DW_CFA_def_cfa_sf(reg=%" PRIu64 ", offset=%" PRId64 ")\n", reg, 612 offset); 613 break; 614 case DW_CFA_def_cfa_offset_sf: 615 results->cfaRegisterOffset = (int32_t) 616 (addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor); 617 results->codeOffsetAtStackDecrement = (uint32_t)codeOffset; 618 if (logDwarf) 619 fprintf(stderr, "DW_CFA_def_cfa_offset_sf(%d)\n", 620 results->cfaRegisterOffset); 621 break; 622 case DW_CFA_val_offset: 623 reg = addressSpace.getULEB128(p, instructionsEnd); 624 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) 625 * cieInfo.dataAlignFactor; 626 results->savedRegisters[reg].location = kRegisterOffsetFromCFA; 627 results->savedRegisters[reg].value = offset; 628 if (logDwarf) 629 fprintf(stderr, 630 "DW_CFA_val_offset(reg=%" PRIu64 ", offset=%" PRId64 "\n", reg, 631 offset); 632 break; 633 case DW_CFA_val_offset_sf: 634 reg = addressSpace.getULEB128(p, instructionsEnd); 635 if (reg > kMaxRegisterNumber) { 636 fprintf(stderr, 637 "malformed DW_CFA_val_offset_sf dwarf unwind, reg too big\n"); 638 return false; 639 } 640 offset = 641 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; 642 results->savedRegisters[reg].location = kRegisterOffsetFromCFA; 643 results->savedRegisters[reg].value = offset; 644 if (logDwarf) 645 fprintf(stderr, 646 "DW_CFA_val_offset_sf(reg=%" PRIu64 ", offset=%" PRId64 "\n", 647 reg, offset); 648 break; 649 case DW_CFA_val_expression: 650 reg = addressSpace.getULEB128(p, instructionsEnd); 651 if (reg > kMaxRegisterNumber) { 652 fprintf(stderr, 653 "malformed DW_CFA_val_expression dwarf unwind, reg too big\n"); 654 return false; 655 } 656 results->savedRegisters[reg].location = kRegisterIsExpression; 657 results->savedRegisters[reg].value = (int64_t)p; 658 length = addressSpace.getULEB128(p, instructionsEnd); 659 p += length; 660 if (logDwarf) 661 fprintf(stderr, "DW_CFA_val_expression(reg=%" PRIu64 662 ", expression=0x%" PRIx64 ", length=%" PRIu64 ")\n", 663 reg, results->savedRegisters[reg].value, length); 664 break; 665 case DW_CFA_GNU_args_size: 666 length = addressSpace.getULEB128(p, instructionsEnd); 667 results->spExtraArgSize = (uint32_t)length; 668 if (logDwarf) 669 fprintf(stderr, "DW_CFA_GNU_args_size(%" PRIu64 ")\n", length); 670 break; 671 case DW_CFA_GNU_negative_offset_extended: 672 reg = addressSpace.getULEB128(p, instructionsEnd); 673 if (reg > kMaxRegisterNumber) { 674 fprintf(stderr, "malformed DW_CFA_GNU_negative_offset_extended dwarf " 675 "unwind, reg too big\n"); 676 return false; 677 } 678 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) 679 * cieInfo.dataAlignFactor; 680 results->savedRegisters[reg].location = kRegisterInCFA; 681 results->savedRegisters[reg].value = -offset; 682 if (logDwarf) 683 fprintf(stderr, "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", 684 offset); 685 break; 686 default: 687 operand = opcode & 0x3F; 688 switch (opcode & 0xC0) { 689 case DW_CFA_offset: 690 reg = operand; 691 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) 692 * cieInfo.dataAlignFactor; 693 results->savedRegisters[reg].location = kRegisterInCFA; 694 results->savedRegisters[reg].value = offset; 695 if (logDwarf) 696 fprintf(stderr, "DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n", 697 operand, offset); 698 break; 699 case DW_CFA_advance_loc: 700 codeOffset += operand * cieInfo.codeAlignFactor; 701 if (logDwarf) 702 fprintf(stderr, "DW_CFA_advance_loc: new offset=%" PRIu64 "\n", 703 (uint64_t)codeOffset); 704 break; 705 case DW_CFA_restore: 706 reg = operand; 707 results->savedRegisters[reg] = initialState.savedRegisters[reg]; 708 if (logDwarf) 709 fprintf(stderr, "DW_CFA_restore(reg=%" PRIu64 ")\n", reg); 710 break; 711 default: 712 if (logDwarf) 713 fprintf(stderr, "unknown CFA opcode 0x%02X\n", opcode); 714 return false; 715 } 716 } 717 } 718 719 return true; 720 } 721 722 } // namespace libunwind 723 724 #endif // __DWARF_PARSER_HPP__ 725