DwarfParser.hpp revision 288151
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 26namespace 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/// 32template <typename A> 33class CFI_Parser { 34public: 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 = 120 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 110private: 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 119template <typename A> 120const 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 174template <typename A> 175bool 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 254template <typename A> 255const 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 342template <typename A> 343bool 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 361template <typename A> 362bool 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 PrologInfoStackEntry *entry; 384 ++p; 385 switch (opcode) { 386 case DW_CFA_nop: 387 if (logDwarf) 388 fprintf(stderr, "DW_CFA_nop\n"); 389 break; 390 case DW_CFA_set_loc: 391 codeOffset = 392 addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding); 393 if (logDwarf) 394 fprintf(stderr, "DW_CFA_set_loc\n"); 395 break; 396 case DW_CFA_advance_loc1: 397 codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor); 398 p += 1; 399 if (logDwarf) 400 fprintf(stderr, "DW_CFA_advance_loc1: new offset=%" PRIu64 "\n", 401 (uint64_t)codeOffset); 402 break; 403 case DW_CFA_advance_loc2: 404 codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor); 405 p += 2; 406 if (logDwarf) 407 fprintf(stderr, "DW_CFA_advance_loc2: new offset=%" PRIu64 "\n", 408 (uint64_t)codeOffset); 409 break; 410 case DW_CFA_advance_loc4: 411 codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor); 412 p += 4; 413 if (logDwarf) 414 fprintf(stderr, "DW_CFA_advance_loc4: new offset=%" PRIu64 "\n", 415 (uint64_t)codeOffset); 416 break; 417 case DW_CFA_offset_extended: 418 reg = addressSpace.getULEB128(p, instructionsEnd); 419 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) 420 * cieInfo.dataAlignFactor; 421 if (reg > kMaxRegisterNumber) { 422 fprintf(stderr, 423 "malformed DW_CFA_offset_extended dwarf unwind, reg too big\n"); 424 return false; 425 } 426 results->savedRegisters[reg].location = kRegisterInCFA; 427 results->savedRegisters[reg].value = offset; 428 if (logDwarf) 429 fprintf(stderr, 430 "DW_CFA_offset_extended(reg=%" PRIu64 ", offset=%" PRId64 ")\n", 431 reg, offset); 432 break; 433 case DW_CFA_restore_extended: 434 reg = addressSpace.getULEB128(p, instructionsEnd); 435 ; 436 if (reg > kMaxRegisterNumber) { 437 fprintf( 438 stderr, 439 "malformed DW_CFA_restore_extended dwarf unwind, reg too big\n"); 440 return false; 441 } 442 results->savedRegisters[reg] = initialState.savedRegisters[reg]; 443 if (logDwarf) 444 fprintf(stderr, "DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg); 445 break; 446 case DW_CFA_undefined: 447 reg = addressSpace.getULEB128(p, instructionsEnd); 448 if (reg > kMaxRegisterNumber) { 449 fprintf(stderr, 450 "malformed DW_CFA_undefined dwarf unwind, reg too big\n"); 451 return false; 452 } 453 results->savedRegisters[reg].location = kRegisterUnused; 454 if (logDwarf) 455 fprintf(stderr, "DW_CFA_undefined(reg=%" PRIu64 ")\n", reg); 456 break; 457 case DW_CFA_same_value: 458 reg = addressSpace.getULEB128(p, instructionsEnd); 459 if (reg > kMaxRegisterNumber) { 460 fprintf(stderr, 461 "malformed DW_CFA_same_value dwarf unwind, reg too big\n"); 462 return false; 463 } 464 // <rdar://problem/8456377> DW_CFA_same_value unsupported 465 // "same value" means register was stored in frame, but its current 466 // value has not changed, so no need to restore from frame. 467 // We model this as if the register was never saved. 468 results->savedRegisters[reg].location = kRegisterUnused; 469 // set flag to disable conversion to compact unwind 470 results->sameValueUsed = true; 471 if (logDwarf) 472 fprintf(stderr, "DW_CFA_same_value(reg=%" PRIu64 ")\n", reg); 473 break; 474 case DW_CFA_register: 475 reg = addressSpace.getULEB128(p, instructionsEnd); 476 reg2 = addressSpace.getULEB128(p, instructionsEnd); 477 if (reg > kMaxRegisterNumber) { 478 fprintf(stderr, 479 "malformed DW_CFA_register dwarf unwind, reg too big\n"); 480 return false; 481 } 482 if (reg2 > kMaxRegisterNumber) { 483 fprintf(stderr, 484 "malformed DW_CFA_register dwarf unwind, reg2 too big\n"); 485 return false; 486 } 487 results->savedRegisters[reg].location = kRegisterInRegister; 488 results->savedRegisters[reg].value = (int64_t)reg2; 489 // set flag to disable conversion to compact unwind 490 results->registersInOtherRegisters = true; 491 if (logDwarf) 492 fprintf(stderr, "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", 493 reg, reg2); 494 break; 495 case DW_CFA_remember_state: 496 // avoid operator new, because that would be an upward dependency 497 entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry)); 498 if (entry != NULL) { 499 entry->next = rememberStack; 500 entry->info = *results; 501 rememberStack = entry; 502 } else { 503 return false; 504 } 505 if (logDwarf) 506 fprintf(stderr, "DW_CFA_remember_state\n"); 507 break; 508 case DW_CFA_restore_state: 509 if (rememberStack != NULL) { 510 PrologInfoStackEntry *top = rememberStack; 511 *results = top->info; 512 rememberStack = top->next; 513 free((char *)top); 514 } else { 515 return false; 516 } 517 if (logDwarf) 518 fprintf(stderr, "DW_CFA_restore_state\n"); 519 break; 520 case DW_CFA_def_cfa: 521 reg = addressSpace.getULEB128(p, instructionsEnd); 522 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd); 523 if (reg > kMaxRegisterNumber) { 524 fprintf(stderr, "malformed DW_CFA_def_cfa dwarf unwind, reg too big\n"); 525 return false; 526 } 527 results->cfaRegister = (uint32_t)reg; 528 results->cfaRegisterOffset = (int32_t)offset; 529 if (logDwarf) 530 fprintf(stderr, "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", 531 reg, offset); 532 break; 533 case DW_CFA_def_cfa_register: 534 reg = addressSpace.getULEB128(p, instructionsEnd); 535 if (reg > kMaxRegisterNumber) { 536 fprintf( 537 stderr, 538 "malformed DW_CFA_def_cfa_register dwarf unwind, reg too big\n"); 539 return false; 540 } 541 results->cfaRegister = (uint32_t)reg; 542 if (logDwarf) 543 fprintf(stderr, "DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg); 544 break; 545 case DW_CFA_def_cfa_offset: 546 results->cfaRegisterOffset = (int32_t) 547 addressSpace.getULEB128(p, instructionsEnd); 548 results->codeOffsetAtStackDecrement = (uint32_t)codeOffset; 549 if (logDwarf) 550 fprintf(stderr, "DW_CFA_def_cfa_offset(%d)\n", 551 results->cfaRegisterOffset); 552 break; 553 case DW_CFA_def_cfa_expression: 554 results->cfaRegister = 0; 555 results->cfaExpression = (int64_t)p; 556 length = addressSpace.getULEB128(p, instructionsEnd); 557 p += length; 558 if (logDwarf) 559 fprintf(stderr, "DW_CFA_def_cfa_expression(expression=0x%" PRIx64 560 ", length=%" PRIu64 ")\n", 561 results->cfaExpression, length); 562 break; 563 case DW_CFA_expression: 564 reg = addressSpace.getULEB128(p, instructionsEnd); 565 if (reg > kMaxRegisterNumber) { 566 fprintf(stderr, 567 "malformed DW_CFA_expression dwarf unwind, reg too big\n"); 568 return false; 569 } 570 results->savedRegisters[reg].location = kRegisterAtExpression; 571 results->savedRegisters[reg].value = (int64_t)p; 572 length = addressSpace.getULEB128(p, instructionsEnd); 573 p += length; 574 if (logDwarf) 575 fprintf(stderr, "DW_CFA_expression(reg=%" PRIu64 576 ", expression=0x%" PRIx64 ", length=%" PRIu64 ")\n", 577 reg, results->savedRegisters[reg].value, length); 578 break; 579 case DW_CFA_offset_extended_sf: 580 reg = addressSpace.getULEB128(p, instructionsEnd); 581 if (reg > kMaxRegisterNumber) { 582 fprintf( 583 stderr, 584 "malformed DW_CFA_offset_extended_sf dwarf unwind, reg too big\n"); 585 return false; 586 } 587 offset = 588 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; 589 results->savedRegisters[reg].location = kRegisterInCFA; 590 results->savedRegisters[reg].value = offset; 591 if (logDwarf) 592 fprintf(stderr, "DW_CFA_offset_extended_sf(reg=%" PRIu64 593 ", offset=%" PRId64 ")\n", 594 reg, offset); 595 break; 596 case DW_CFA_def_cfa_sf: 597 reg = addressSpace.getULEB128(p, instructionsEnd); 598 offset = 599 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; 600 if (reg > kMaxRegisterNumber) { 601 fprintf(stderr, 602 "malformed DW_CFA_def_cfa_sf dwarf unwind, reg too big\n"); 603 return false; 604 } 605 results->cfaRegister = (uint32_t)reg; 606 results->cfaRegisterOffset = (int32_t)offset; 607 if (logDwarf) 608 fprintf(stderr, 609 "DW_CFA_def_cfa_sf(reg=%" PRIu64 ", offset=%" PRId64 ")\n", reg, 610 offset); 611 break; 612 case DW_CFA_def_cfa_offset_sf: 613 results->cfaRegisterOffset = (int32_t) 614 (addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor); 615 results->codeOffsetAtStackDecrement = (uint32_t)codeOffset; 616 if (logDwarf) 617 fprintf(stderr, "DW_CFA_def_cfa_offset_sf(%d)\n", 618 results->cfaRegisterOffset); 619 break; 620 case DW_CFA_val_offset: 621 reg = addressSpace.getULEB128(p, instructionsEnd); 622 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) 623 * cieInfo.dataAlignFactor; 624 results->savedRegisters[reg].location = kRegisterOffsetFromCFA; 625 results->savedRegisters[reg].value = offset; 626 if (logDwarf) 627 fprintf(stderr, 628 "DW_CFA_val_offset(reg=%" PRIu64 ", offset=%" PRId64 "\n", reg, 629 offset); 630 break; 631 case DW_CFA_val_offset_sf: 632 reg = addressSpace.getULEB128(p, instructionsEnd); 633 if (reg > kMaxRegisterNumber) { 634 fprintf(stderr, 635 "malformed DW_CFA_val_offset_sf dwarf unwind, reg too big\n"); 636 return false; 637 } 638 offset = 639 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; 640 results->savedRegisters[reg].location = kRegisterOffsetFromCFA; 641 results->savedRegisters[reg].value = offset; 642 if (logDwarf) 643 fprintf(stderr, 644 "DW_CFA_val_offset_sf(reg=%" PRIu64 ", offset=%" PRId64 "\n", 645 reg, offset); 646 break; 647 case DW_CFA_val_expression: 648 reg = addressSpace.getULEB128(p, instructionsEnd); 649 if (reg > kMaxRegisterNumber) { 650 fprintf(stderr, 651 "malformed DW_CFA_val_expression dwarf unwind, reg too big\n"); 652 return false; 653 } 654 results->savedRegisters[reg].location = kRegisterIsExpression; 655 results->savedRegisters[reg].value = (int64_t)p; 656 length = addressSpace.getULEB128(p, instructionsEnd); 657 p += length; 658 if (logDwarf) 659 fprintf(stderr, "DW_CFA_val_expression(reg=%" PRIu64 660 ", expression=0x%" PRIx64 ", length=%" PRIu64 ")\n", 661 reg, results->savedRegisters[reg].value, length); 662 break; 663 case DW_CFA_GNU_args_size: 664 length = addressSpace.getULEB128(p, instructionsEnd); 665 results->spExtraArgSize = (uint32_t)length; 666 if (logDwarf) 667 fprintf(stderr, "DW_CFA_GNU_args_size(%" PRIu64 ")\n", length); 668 break; 669 case DW_CFA_GNU_negative_offset_extended: 670 reg = addressSpace.getULEB128(p, instructionsEnd); 671 if (reg > kMaxRegisterNumber) { 672 fprintf(stderr, "malformed DW_CFA_GNU_negative_offset_extended dwarf " 673 "unwind, reg too big\n"); 674 return false; 675 } 676 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) 677 * cieInfo.dataAlignFactor; 678 results->savedRegisters[reg].location = kRegisterInCFA; 679 results->savedRegisters[reg].value = -offset; 680 if (logDwarf) 681 fprintf(stderr, "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", 682 offset); 683 break; 684 default: 685 operand = opcode & 0x3F; 686 switch (opcode & 0xC0) { 687 case DW_CFA_offset: 688 reg = operand; 689 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) 690 * cieInfo.dataAlignFactor; 691 results->savedRegisters[reg].location = kRegisterInCFA; 692 results->savedRegisters[reg].value = offset; 693 if (logDwarf) 694 fprintf(stderr, "DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n", 695 operand, offset); 696 break; 697 case DW_CFA_advance_loc: 698 codeOffset += operand * cieInfo.codeAlignFactor; 699 if (logDwarf) 700 fprintf(stderr, "DW_CFA_advance_loc: new offset=%" PRIu64 "\n", 701 (uint64_t)codeOffset); 702 break; 703 case DW_CFA_restore: 704 reg = operand; 705 results->savedRegisters[reg] = initialState.savedRegisters[reg]; 706 if (logDwarf) 707 fprintf(stderr, "DW_CFA_restore(reg=%" PRIu64 ")\n", reg); 708 break; 709 default: 710 if (logDwarf) 711 fprintf(stderr, "unknown CFA opcode 0x%02X\n", opcode); 712 return false; 713 } 714 } 715 } 716 717 return true; 718} 719 720} // namespace libunwind 721 722#endif // __DWARF_PARSER_HPP__ 723