1 //===--------------------------- DwarfParser.hpp --------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 // 8 // Parses DWARF CFIs (FDEs and CIEs). 9 // 10 //===----------------------------------------------------------------------===// 11 12 #ifndef __DWARF_PARSER_HPP__ 13 #define __DWARF_PARSER_HPP__ 14 15 #include <inttypes.h> 16 #include <stdint.h> 17 #include <stdio.h> 18 #include <stdlib.h> 19 20 #include "libunwind.h" 21 #include "dwarf2.h" 22 #include "Registers.hpp" 23 24 #include "config.h" 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 #if defined(_LIBUNWIND_TARGET_AARCH64) 53 bool addressesSignedWithBKey; 54 #endif 55 }; 56 57 /// Information about an FDE (Frame Description Entry) 58 struct FDE_Info { 59 pint_t fdeStart; 60 pint_t fdeLength; 61 pint_t fdeInstructions; 62 pint_t pcStart; 63 pint_t pcEnd; 64 pint_t lsda; 65 }; 66 67 enum { 68 kMaxRegisterNumber = _LIBUNWIND_HIGHEST_DWARF_REGISTER 69 }; 70 enum RegisterSavedWhere { 71 kRegisterUnused, 72 kRegisterInCFA, 73 kRegisterOffsetFromCFA, 74 kRegisterInRegister, 75 kRegisterAtExpression, 76 kRegisterIsExpression 77 }; 78 struct RegisterLocation { 79 RegisterSavedWhere location; 80 int64_t value; 81 }; 82 /// Information about a frame layout and registers saved determined 83 /// by "running" the DWARF FDE "instructions" 84 struct PrologInfo { 85 uint32_t cfaRegister; 86 int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset 87 int64_t cfaExpression; // CFA = expression 88 uint32_t spExtraArgSize; 89 uint32_t codeOffsetAtStackDecrement; 90 bool registersInOtherRegisters; 91 bool sameValueUsed; 92 RegisterLocation savedRegisters[kMaxRegisterNumber + 1]; 93 }; 94 95 struct PrologInfoStackEntry { 96 PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i) 97 : next(n), info(i) {} 98 PrologInfoStackEntry *next; 99 PrologInfo info; 100 }; 101 102 static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, 103 uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo, 104 CIE_Info *cieInfo); 105 static const char *decodeFDE(A &addressSpace, pint_t fdeStart, 106 FDE_Info *fdeInfo, CIE_Info *cieInfo); 107 static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo, 108 const CIE_Info &cieInfo, pint_t upToPC, 109 int arch, PrologInfo *results); 110 111 static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo); 112 113 private: 114 static bool parseInstructions(A &addressSpace, pint_t instructions, 115 pint_t instructionsEnd, const CIE_Info &cieInfo, 116 pint_t pcoffset, 117 PrologInfoStackEntry *&rememberStack, int arch, 118 PrologInfo *results); 119 }; 120 121 /// Parse a FDE into a CIE_Info and an FDE_Info 122 template <typename A> 123 const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart, 124 FDE_Info *fdeInfo, CIE_Info *cieInfo) { 125 pint_t p = fdeStart; 126 pint_t cfiLength = (pint_t)addressSpace.get32(p); 127 p += 4; 128 if (cfiLength == 0xffffffff) { 129 // 0xffffffff means length is really next 8 bytes 130 cfiLength = (pint_t)addressSpace.get64(p); 131 p += 8; 132 } 133 if (cfiLength == 0) 134 return "FDE has zero length"; // end marker 135 uint32_t ciePointer = addressSpace.get32(p); 136 if (ciePointer == 0) 137 return "FDE is really a CIE"; // this is a CIE not an FDE 138 pint_t nextCFI = p + cfiLength; 139 pint_t cieStart = p - ciePointer; 140 const char *err = parseCIE(addressSpace, cieStart, cieInfo); 141 if (err != NULL) 142 return err; 143 p += 4; 144 // Parse pc begin and range. 145 pint_t pcStart = 146 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding); 147 pint_t pcRange = 148 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F); 149 // Parse rest of info. 150 fdeInfo->lsda = 0; 151 // Check for augmentation length. 152 if (cieInfo->fdesHaveAugmentationData) { 153 pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI); 154 pint_t endOfAug = p + augLen; 155 if (cieInfo->lsdaEncoding != DW_EH_PE_omit) { 156 // Peek at value (without indirection). Zero means no LSDA. 157 pint_t lsdaStart = p; 158 if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 159 0) { 160 // Reset pointer and re-parse LSDA address. 161 p = lsdaStart; 162 fdeInfo->lsda = 163 addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); 164 } 165 } 166 p = endOfAug; 167 } 168 fdeInfo->fdeStart = fdeStart; 169 fdeInfo->fdeLength = nextCFI - fdeStart; 170 fdeInfo->fdeInstructions = p; 171 fdeInfo->pcStart = pcStart; 172 fdeInfo->pcEnd = pcStart + pcRange; 173 return NULL; // success 174 } 175 176 /// Scan an eh_frame section to find an FDE for a pc 177 template <typename A> 178 bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, 179 uint32_t sectionLength, pint_t fdeHint, 180 FDE_Info *fdeInfo, CIE_Info *cieInfo) { 181 //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc); 182 pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart; 183 const pint_t ehSectionEnd = p + sectionLength; 184 while (p < ehSectionEnd) { 185 pint_t currentCFI = p; 186 //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p); 187 pint_t cfiLength = addressSpace.get32(p); 188 p += 4; 189 if (cfiLength == 0xffffffff) { 190 // 0xffffffff means length is really next 8 bytes 191 cfiLength = (pint_t)addressSpace.get64(p); 192 p += 8; 193 } 194 if (cfiLength == 0) 195 return false; // end marker 196 uint32_t id = addressSpace.get32(p); 197 if (id == 0) { 198 // Skip over CIEs. 199 p += cfiLength; 200 } else { 201 // Process FDE to see if it covers pc. 202 pint_t nextCFI = p + cfiLength; 203 uint32_t ciePointer = addressSpace.get32(p); 204 pint_t cieStart = p - ciePointer; 205 // Validate pointer to CIE is within section. 206 if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) { 207 if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) { 208 p += 4; 209 // Parse pc begin and range. 210 pint_t pcStart = 211 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding); 212 pint_t pcRange = addressSpace.getEncodedP( 213 p, nextCFI, cieInfo->pointerEncoding & 0x0F); 214 // Test if pc is within the function this FDE covers. 215 if ((pcStart < pc) && (pc <= pcStart + pcRange)) { 216 // parse rest of info 217 fdeInfo->lsda = 0; 218 // check for augmentation length 219 if (cieInfo->fdesHaveAugmentationData) { 220 pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI); 221 pint_t endOfAug = p + augLen; 222 if (cieInfo->lsdaEncoding != DW_EH_PE_omit) { 223 // Peek at value (without indirection). Zero means no LSDA. 224 pint_t lsdaStart = p; 225 if (addressSpace.getEncodedP( 226 p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) { 227 // Reset pointer and re-parse LSDA address. 228 p = lsdaStart; 229 fdeInfo->lsda = addressSpace 230 .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); 231 } 232 } 233 p = endOfAug; 234 } 235 fdeInfo->fdeStart = currentCFI; 236 fdeInfo->fdeLength = nextCFI - currentCFI; 237 fdeInfo->fdeInstructions = p; 238 fdeInfo->pcStart = pcStart; 239 fdeInfo->pcEnd = pcStart + pcRange; 240 return true; 241 } else { 242 // pc is not in begin/range, skip this FDE 243 } 244 } else { 245 // Malformed CIE, now augmentation describing pc range encoding. 246 } 247 } else { 248 // malformed FDE. CIE is bad 249 } 250 p = nextCFI; 251 } 252 } 253 return false; 254 } 255 256 /// Extract info from a CIE 257 template <typename A> 258 const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie, 259 CIE_Info *cieInfo) { 260 cieInfo->pointerEncoding = 0; 261 cieInfo->lsdaEncoding = DW_EH_PE_omit; 262 cieInfo->personalityEncoding = 0; 263 cieInfo->personalityOffsetInCIE = 0; 264 cieInfo->personality = 0; 265 cieInfo->codeAlignFactor = 0; 266 cieInfo->dataAlignFactor = 0; 267 cieInfo->isSignalFrame = false; 268 cieInfo->fdesHaveAugmentationData = false; 269 #if defined(_LIBUNWIND_TARGET_AARCH64) 270 cieInfo->addressesSignedWithBKey = false; 271 #endif 272 cieInfo->cieStart = cie; 273 pint_t p = cie; 274 pint_t cieLength = (pint_t)addressSpace.get32(p); 275 p += 4; 276 pint_t cieContentEnd = p + cieLength; 277 if (cieLength == 0xffffffff) { 278 // 0xffffffff means length is really next 8 bytes 279 cieLength = (pint_t)addressSpace.get64(p); 280 p += 8; 281 cieContentEnd = p + cieLength; 282 } 283 if (cieLength == 0) 284 return NULL; 285 // CIE ID is always 0 286 if (addressSpace.get32(p) != 0) 287 return "CIE ID is not zero"; 288 p += 4; 289 // Version is always 1 or 3 290 uint8_t version = addressSpace.get8(p); 291 if ((version != 1) && (version != 3)) 292 return "CIE version is not 1 or 3"; 293 ++p; 294 // save start of augmentation string and find end 295 pint_t strStart = p; 296 while (addressSpace.get8(p) != 0) 297 ++p; 298 ++p; 299 // parse code aligment factor 300 cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd); 301 // parse data alignment factor 302 cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd); 303 // parse return address register 304 uint64_t raReg = addressSpace.getULEB128(p, cieContentEnd); 305 assert(raReg < 255 && "return address register too large"); 306 cieInfo->returnAddressRegister = (uint8_t)raReg; 307 // parse augmentation data based on augmentation string 308 const char *result = NULL; 309 if (addressSpace.get8(strStart) == 'z') { 310 // parse augmentation data length 311 addressSpace.getULEB128(p, cieContentEnd); 312 for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) { 313 switch (addressSpace.get8(s)) { 314 case 'z': 315 cieInfo->fdesHaveAugmentationData = true; 316 break; 317 case 'P': 318 cieInfo->personalityEncoding = addressSpace.get8(p); 319 ++p; 320 cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie); 321 cieInfo->personality = addressSpace 322 .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding); 323 break; 324 case 'L': 325 cieInfo->lsdaEncoding = addressSpace.get8(p); 326 ++p; 327 break; 328 case 'R': 329 cieInfo->pointerEncoding = addressSpace.get8(p); 330 ++p; 331 break; 332 case 'S': 333 cieInfo->isSignalFrame = true; 334 break; 335 #if defined(_LIBUNWIND_TARGET_AARCH64) 336 case 'B': 337 cieInfo->addressesSignedWithBKey = true; 338 break; 339 #endif 340 default: 341 // ignore unknown letters 342 break; 343 } 344 } 345 } 346 cieInfo->cieLength = cieContentEnd - cieInfo->cieStart; 347 cieInfo->cieInstructions = p; 348 return result; 349 } 350 351 352 /// "run" the DWARF instructions and create the abstact PrologInfo for an FDE 353 template <typename A> 354 bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace, 355 const FDE_Info &fdeInfo, 356 const CIE_Info &cieInfo, pint_t upToPC, 357 int arch, PrologInfo *results) { 358 // clear results 359 memset(results, '\0', sizeof(PrologInfo)); 360 PrologInfoStackEntry *rememberStack = NULL; 361 362 // parse CIE then FDE instructions 363 return parseInstructions(addressSpace, cieInfo.cieInstructions, 364 cieInfo.cieStart + cieInfo.cieLength, cieInfo, 365 (pint_t)(-1), rememberStack, arch, results) && 366 parseInstructions(addressSpace, fdeInfo.fdeInstructions, 367 fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo, 368 upToPC - fdeInfo.pcStart, rememberStack, arch, 369 results); 370 } 371 372 /// "run" the DWARF instructions 373 template <typename A> 374 bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions, 375 pint_t instructionsEnd, 376 const CIE_Info &cieInfo, pint_t pcoffset, 377 PrologInfoStackEntry *&rememberStack, 378 int arch, PrologInfo *results) { 379 pint_t p = instructions; 380 pint_t codeOffset = 0; 381 PrologInfo initialState = *results; 382 383 _LIBUNWIND_TRACE_DWARF("parseInstructions(instructions=0x%0" PRIx64 ")\n", 384 static_cast<uint64_t>(instructionsEnd)); 385 386 // see DWARF Spec, section 6.4.2 for details on unwind opcodes 387 while ((p < instructionsEnd) && (codeOffset < pcoffset)) { 388 uint64_t reg; 389 uint64_t reg2; 390 int64_t offset; 391 uint64_t length; 392 uint8_t opcode = addressSpace.get8(p); 393 uint8_t operand; 394 #if !defined(_LIBUNWIND_NO_HEAP) 395 PrologInfoStackEntry *entry; 396 #endif 397 ++p; 398 switch (opcode) { 399 case DW_CFA_nop: 400 _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n"); 401 break; 402 case DW_CFA_set_loc: 403 codeOffset = 404 addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding); 405 _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n"); 406 break; 407 case DW_CFA_advance_loc1: 408 codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor); 409 p += 1; 410 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n", 411 static_cast<uint64_t>(codeOffset)); 412 break; 413 case DW_CFA_advance_loc2: 414 codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor); 415 p += 2; 416 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n", 417 static_cast<uint64_t>(codeOffset)); 418 break; 419 case DW_CFA_advance_loc4: 420 codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor); 421 p += 4; 422 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n", 423 static_cast<uint64_t>(codeOffset)); 424 break; 425 case DW_CFA_offset_extended: 426 reg = addressSpace.getULEB128(p, instructionsEnd); 427 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) 428 * cieInfo.dataAlignFactor; 429 if (reg > kMaxRegisterNumber) { 430 _LIBUNWIND_LOG0( 431 "malformed DW_CFA_offset_extended DWARF unwind, reg too big"); 432 return false; 433 } 434 results->savedRegisters[reg].location = kRegisterInCFA; 435 results->savedRegisters[reg].value = offset; 436 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", " 437 "offset=%" PRId64 ")\n", 438 reg, offset); 439 break; 440 case DW_CFA_restore_extended: 441 reg = addressSpace.getULEB128(p, instructionsEnd); 442 if (reg > kMaxRegisterNumber) { 443 _LIBUNWIND_LOG0( 444 "malformed DW_CFA_restore_extended DWARF unwind, reg too big"); 445 return false; 446 } 447 results->savedRegisters[reg] = initialState.savedRegisters[reg]; 448 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg); 449 break; 450 case DW_CFA_undefined: 451 reg = addressSpace.getULEB128(p, instructionsEnd); 452 if (reg > kMaxRegisterNumber) { 453 _LIBUNWIND_LOG0( 454 "malformed DW_CFA_undefined DWARF unwind, reg too big"); 455 return false; 456 } 457 results->savedRegisters[reg].location = kRegisterUnused; 458 _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg); 459 break; 460 case DW_CFA_same_value: 461 reg = addressSpace.getULEB128(p, instructionsEnd); 462 if (reg > kMaxRegisterNumber) { 463 _LIBUNWIND_LOG0( 464 "malformed DW_CFA_same_value DWARF unwind, reg too big"); 465 return false; 466 } 467 // <rdar://problem/8456377> DW_CFA_same_value unsupported 468 // "same value" means register was stored in frame, but its current 469 // value has not changed, so no need to restore from frame. 470 // We model this as if the register was never saved. 471 results->savedRegisters[reg].location = kRegisterUnused; 472 // set flag to disable conversion to compact unwind 473 results->sameValueUsed = true; 474 _LIBUNWIND_TRACE_DWARF("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 _LIBUNWIND_LOG0( 481 "malformed DW_CFA_register DWARF unwind, reg too big"); 482 return false; 483 } 484 if (reg2 > kMaxRegisterNumber) { 485 _LIBUNWIND_LOG0( 486 "malformed DW_CFA_register DWARF unwind, reg2 too big"); 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 _LIBUNWIND_TRACE_DWARF( 494 "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2); 495 break; 496 #if !defined(_LIBUNWIND_NO_HEAP) 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 _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n"); 508 break; 509 case DW_CFA_restore_state: 510 if (rememberStack != NULL) { 511 PrologInfoStackEntry *top = rememberStack; 512 *results = top->info; 513 rememberStack = top->next; 514 free((char *)top); 515 } else { 516 return false; 517 } 518 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n"); 519 break; 520 #endif 521 case DW_CFA_def_cfa: 522 reg = addressSpace.getULEB128(p, instructionsEnd); 523 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd); 524 if (reg > kMaxRegisterNumber) { 525 _LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big"); 526 return false; 527 } 528 results->cfaRegister = (uint32_t)reg; 529 results->cfaRegisterOffset = (int32_t)offset; 530 _LIBUNWIND_TRACE_DWARF( 531 "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", reg, offset); 532 break; 533 case DW_CFA_def_cfa_register: 534 reg = addressSpace.getULEB128(p, instructionsEnd); 535 if (reg > kMaxRegisterNumber) { 536 _LIBUNWIND_LOG0( 537 "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big"); 538 return false; 539 } 540 results->cfaRegister = (uint32_t)reg; 541 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg); 542 break; 543 case DW_CFA_def_cfa_offset: 544 results->cfaRegisterOffset = (int32_t) 545 addressSpace.getULEB128(p, instructionsEnd); 546 results->codeOffsetAtStackDecrement = (uint32_t)codeOffset; 547 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n", 548 results->cfaRegisterOffset); 549 break; 550 case DW_CFA_def_cfa_expression: 551 results->cfaRegister = 0; 552 results->cfaExpression = (int64_t)p; 553 length = addressSpace.getULEB128(p, instructionsEnd); 554 assert(length < static_cast<pint_t>(~0) && "pointer overflow"); 555 p += static_cast<pint_t>(length); 556 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64 557 ", length=%" PRIu64 ")\n", 558 results->cfaExpression, length); 559 break; 560 case DW_CFA_expression: 561 reg = addressSpace.getULEB128(p, instructionsEnd); 562 if (reg > kMaxRegisterNumber) { 563 _LIBUNWIND_LOG0( 564 "malformed DW_CFA_expression DWARF unwind, reg too big"); 565 return false; 566 } 567 results->savedRegisters[reg].location = kRegisterAtExpression; 568 results->savedRegisters[reg].value = (int64_t)p; 569 length = addressSpace.getULEB128(p, instructionsEnd); 570 assert(length < static_cast<pint_t>(~0) && "pointer overflow"); 571 p += static_cast<pint_t>(length); 572 _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", " 573 "expression=0x%" PRIx64 ", " 574 "length=%" PRIu64 ")\n", 575 reg, results->savedRegisters[reg].value, length); 576 break; 577 case DW_CFA_offset_extended_sf: 578 reg = addressSpace.getULEB128(p, instructionsEnd); 579 if (reg > kMaxRegisterNumber) { 580 _LIBUNWIND_LOG0( 581 "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big"); 582 return false; 583 } 584 offset = 585 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; 586 results->savedRegisters[reg].location = kRegisterInCFA; 587 results->savedRegisters[reg].value = offset; 588 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", " 589 "offset=%" PRId64 ")\n", 590 reg, offset); 591 break; 592 case DW_CFA_def_cfa_sf: 593 reg = addressSpace.getULEB128(p, instructionsEnd); 594 offset = 595 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; 596 if (reg > kMaxRegisterNumber) { 597 _LIBUNWIND_LOG0( 598 "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big"); 599 return false; 600 } 601 results->cfaRegister = (uint32_t)reg; 602 results->cfaRegisterOffset = (int32_t)offset; 603 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", " 604 "offset=%" PRId64 ")\n", 605 reg, offset); 606 break; 607 case DW_CFA_def_cfa_offset_sf: 608 results->cfaRegisterOffset = (int32_t) 609 (addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor); 610 results->codeOffsetAtStackDecrement = (uint32_t)codeOffset; 611 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n", 612 results->cfaRegisterOffset); 613 break; 614 case DW_CFA_val_offset: 615 reg = addressSpace.getULEB128(p, instructionsEnd); 616 if (reg > kMaxRegisterNumber) { 617 _LIBUNWIND_LOG( 618 "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64 619 ") out of range\n", 620 reg); 621 return false; 622 } 623 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) 624 * cieInfo.dataAlignFactor; 625 results->savedRegisters[reg].location = kRegisterOffsetFromCFA; 626 results->savedRegisters[reg].value = offset; 627 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", " 628 "offset=%" PRId64 "\n", 629 reg, offset); 630 break; 631 case DW_CFA_val_offset_sf: 632 reg = addressSpace.getULEB128(p, instructionsEnd); 633 if (reg > kMaxRegisterNumber) { 634 _LIBUNWIND_LOG0( 635 "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big"); 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 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", " 643 "offset=%" PRId64 "\n", 644 reg, offset); 645 break; 646 case DW_CFA_val_expression: 647 reg = addressSpace.getULEB128(p, instructionsEnd); 648 if (reg > kMaxRegisterNumber) { 649 _LIBUNWIND_LOG0( 650 "malformed DW_CFA_val_expression DWARF unwind, reg too big"); 651 return false; 652 } 653 results->savedRegisters[reg].location = kRegisterIsExpression; 654 results->savedRegisters[reg].value = (int64_t)p; 655 length = addressSpace.getULEB128(p, instructionsEnd); 656 assert(length < static_cast<pint_t>(~0) && "pointer overflow"); 657 p += static_cast<pint_t>(length); 658 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", " 659 "expression=0x%" PRIx64 ", length=%" PRIu64 ")\n", 660 reg, results->savedRegisters[reg].value, length); 661 break; 662 case DW_CFA_GNU_args_size: 663 length = addressSpace.getULEB128(p, instructionsEnd); 664 results->spExtraArgSize = (uint32_t)length; 665 _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length); 666 break; 667 case DW_CFA_GNU_negative_offset_extended: 668 reg = addressSpace.getULEB128(p, instructionsEnd); 669 if (reg > kMaxRegisterNumber) { 670 _LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF " 671 "unwind, reg too big"); 672 return false; 673 } 674 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) 675 * cieInfo.dataAlignFactor; 676 results->savedRegisters[reg].location = kRegisterInCFA; 677 results->savedRegisters[reg].value = -offset; 678 _LIBUNWIND_TRACE_DWARF( 679 "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset); 680 break; 681 682 #if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC) 683 // The same constant is used to represent different instructions on 684 // AArch64 (negate_ra_state) and SPARC (window_save). 685 static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save, 686 "uses the same constant"); 687 case DW_CFA_AARCH64_negate_ra_state: 688 switch (arch) { 689 #if defined(_LIBUNWIND_TARGET_AARCH64) 690 case REGISTERS_ARM64: 691 results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^= 0x1; 692 _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n"); 693 break; 694 #endif 695 #if defined(_LIBUNWIND_TARGET_SPARC) 696 // case DW_CFA_GNU_window_save: 697 case REGISTERS_SPARC: 698 _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n"); 699 for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) { 700 results->savedRegisters[reg].location = kRegisterInRegister; 701 results->savedRegisters[reg].value = 702 ((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0; 703 } 704 705 for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) { 706 results->savedRegisters[reg].location = kRegisterInCFA; 707 results->savedRegisters[reg].value = 708 ((int64_t)reg - UNW_SPARC_L0) * 4; 709 } 710 break; 711 #endif 712 } 713 break; 714 #else 715 (void)arch; 716 #endif 717 718 default: 719 operand = opcode & 0x3F; 720 switch (opcode & 0xC0) { 721 case DW_CFA_offset: 722 reg = operand; 723 if (reg > kMaxRegisterNumber) { 724 _LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64 725 ") out of range", 726 reg); 727 return false; 728 } 729 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) 730 * cieInfo.dataAlignFactor; 731 results->savedRegisters[reg].location = kRegisterInCFA; 732 results->savedRegisters[reg].value = offset; 733 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n", 734 operand, offset); 735 break; 736 case DW_CFA_advance_loc: 737 codeOffset += operand * cieInfo.codeAlignFactor; 738 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n", 739 static_cast<uint64_t>(codeOffset)); 740 break; 741 case DW_CFA_restore: 742 reg = operand; 743 if (reg > kMaxRegisterNumber) { 744 _LIBUNWIND_LOG("malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64 745 ") out of range", 746 reg); 747 return false; 748 } 749 results->savedRegisters[reg] = initialState.savedRegisters[reg]; 750 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n", 751 static_cast<uint64_t>(operand)); 752 break; 753 default: 754 _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode); 755 return false; 756 } 757 } 758 } 759 760 return true; 761 } 762 763 } // namespace libunwind 764 765 #endif // __DWARF_PARSER_HPP__ 766