907 lines · plain
1//===----------------------------------------------------------------------===//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-exception6//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#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)27#include <ptrauth.h>28#endif29 30namespace libunwind {31 32/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.33/// See DWARF Spec for details:34/// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html35///36template <typename A>37class CFI_Parser {38public:39 typedef typename A::pint_t pint_t;40 typedef pint_t __ptrauth_unwind_cie_info_personality personality_t;41 42 /// Information encoded in a CIE (Common Information Entry)43 struct CIE_Info {44 pint_t cieStart;45 pint_t cieLength;46 pint_t cieInstructions;47 uint8_t pointerEncoding;48 uint8_t lsdaEncoding;49 uint8_t personalityEncoding;50 uint8_t personalityOffsetInCIE;51 personality_t personality;52 uint32_t codeAlignFactor;53 int dataAlignFactor;54 bool isSignalFrame;55 bool fdesHaveAugmentationData;56 uint8_t returnAddressRegister;57#if defined(_LIBUNWIND_TARGET_AARCH64)58 bool addressesSignedWithBKey;59 bool mteTaggedFrame;60#endif61 };62 63 /// Information about an FDE (Frame Description Entry)64 struct FDE_Info {65 pint_t fdeStart;66 pint_t fdeLength;67 pint_t fdeInstructions;68 pint_t pcStart;69 pint_t pcEnd;70 pint_t lsda;71 };72 73 enum {74 kMaxRegisterNumber = _LIBUNWIND_HIGHEST_DWARF_REGISTER75 };76 enum RegisterSavedWhere {77 kRegisterUnused,78 kRegisterUndefined,79 kRegisterInCFA,80 kRegisterInCFADecrypt, // sparc64 specific81 kRegisterOffsetFromCFA,82 kRegisterInRegister,83 kRegisterAtExpression,84 kRegisterIsExpression85 };86 struct RegisterLocation {87 RegisterSavedWhere location;88 bool initialStateSaved;89 int64_t value;90 };91 /// Information about a frame layout and registers saved determined92 /// by "running" the DWARF FDE "instructions"93 struct PrologInfo {94 uint32_t cfaRegister;95 int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset96 int64_t cfaExpression; // CFA = expression97 uint32_t spExtraArgSize;98 RegisterLocation savedRegisters[kMaxRegisterNumber + 1];99#if defined(_LIBUNWIND_TARGET_AARCH64)100 pint_t ptrAuthDiversifier;101#endif102 enum class InitializeTime { kLazy, kNormal };103 104 // When saving registers, this data structure is lazily initialized.105 PrologInfo(InitializeTime IT = InitializeTime::kNormal) {106 if (IT == InitializeTime::kNormal)107 memset(this, 0, sizeof(*this));108 }109 void checkSaveRegister(uint64_t reg, PrologInfo &initialState) {110 if (!savedRegisters[reg].initialStateSaved) {111 initialState.savedRegisters[reg] = savedRegisters[reg];112 savedRegisters[reg].initialStateSaved = true;113 }114 }115 void setRegister(uint64_t reg, RegisterSavedWhere newLocation,116 int64_t newValue, PrologInfo &initialState) {117 checkSaveRegister(reg, initialState);118 savedRegisters[reg].location = newLocation;119 savedRegisters[reg].value = newValue;120 }121 void setRegisterLocation(uint64_t reg, RegisterSavedWhere newLocation,122 PrologInfo &initialState) {123 checkSaveRegister(reg, initialState);124 savedRegisters[reg].location = newLocation;125 }126 void setRegisterValue(uint64_t reg, int64_t newValue,127 PrologInfo &initialState) {128 checkSaveRegister(reg, initialState);129 savedRegisters[reg].value = newValue;130 }131 void restoreRegisterToInitialState(uint64_t reg, PrologInfo &initialState) {132 if (savedRegisters[reg].initialStateSaved)133 savedRegisters[reg] = initialState.savedRegisters[reg];134 // else the register still holds its initial state135 }136 };137 138 struct PrologInfoStackEntry {139 PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i)140 : next(n), info(i) {}141 PrologInfoStackEntry *next;142 PrologInfo info;143 };144 145 struct RememberStack {146 PrologInfoStackEntry *entry;147 RememberStack() : entry(nullptr) {}148 ~RememberStack() {149#if defined(_LIBUNWIND_REMEMBER_CLEANUP_NEEDED)150 // Clean up rememberStack. Even in the case where every151 // DW_CFA_remember_state is paired with a DW_CFA_restore_state,152 // parseInstructions can skip restore opcodes if it reaches the target PC153 // and stops interpreting, so we have to make sure we don't leak memory.154 while (entry) {155 PrologInfoStackEntry *next = entry->next;156 _LIBUNWIND_REMEMBER_FREE(entry);157 entry = next;158 }159#endif160 }161 };162 163 static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,164 size_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,165 CIE_Info *cieInfo);166 static const char *decodeFDE(A &addressSpace, pint_t fdeStart,167 FDE_Info *fdeInfo, CIE_Info *cieInfo,168 bool useCIEInfo = false);169 static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,170 const CIE_Info &cieInfo, pint_t upToPC,171 int arch, PrologInfo *results);172 173 static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);174};175 176/// Parse a FDE into a CIE_Info and an FDE_Info. If useCIEInfo is177/// true, treat cieInfo as already-parsed CIE_Info (whose start offset178/// must match the one specified by the FDE) rather than parsing the179/// one indicated within the FDE.180template <typename A>181const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,182 FDE_Info *fdeInfo, CIE_Info *cieInfo,183 bool useCIEInfo) {184 pint_t p = fdeStart;185 pint_t cfiLength = (pint_t)addressSpace.get32(p);186 p += 4;187 if (cfiLength == 0xffffffff) {188 // 0xffffffff means length is really next 8 bytes189 cfiLength = (pint_t)addressSpace.get64(p);190 p += 8;191 }192 if (cfiLength == 0)193 return "FDE has zero length"; // zero terminator194 uint32_t ciePointer = addressSpace.get32(p);195 if (ciePointer == 0)196 return "FDE is really a CIE"; // this is a CIE not an FDE197 pint_t nextCFI = p + cfiLength;198 pint_t cieStart = p - ciePointer;199 if (useCIEInfo) {200 if (cieInfo->cieStart != cieStart)201 return "CIE start does not match";202 } else {203 const char *err = parseCIE(addressSpace, cieStart, cieInfo);204 if (err != NULL)205 return err;206 }207 p += 4;208 // Parse pc begin and range.209 pint_t pcStart =210 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);211 pint_t pcRange =212 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);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(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) !=223 0) {224 // Reset pointer and re-parse LSDA address.225 p = lsdaStart;226 fdeInfo->lsda =227 addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);228 }229 }230 p = endOfAug;231 }232 fdeInfo->fdeStart = fdeStart;233 fdeInfo->fdeLength = nextCFI - fdeStart;234 fdeInfo->fdeInstructions = p;235 fdeInfo->pcStart = pcStart;236 fdeInfo->pcEnd = pcStart + pcRange;237 return NULL; // success238}239 240/// Scan an eh_frame section to find an FDE for a pc241template <typename A>242bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,243 size_t sectionLength, pint_t fdeHint,244 FDE_Info *fdeInfo, CIE_Info *cieInfo) {245 //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);246 pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;247 const pint_t ehSectionEnd = (sectionLength == SIZE_MAX)248 ? static_cast<pint_t>(-1)249 : (ehSectionStart + sectionLength);250 while (p < ehSectionEnd) {251 pint_t currentCFI = p;252 //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);253 pint_t cfiLength = addressSpace.get32(p);254 p += 4;255 if (cfiLength == 0xffffffff) {256 // 0xffffffff means length is really next 8 bytes257 cfiLength = (pint_t)addressSpace.get64(p);258 p += 8;259 }260 if (cfiLength == 0)261 return false; // zero terminator262 uint32_t id = addressSpace.get32(p);263 if (id == 0) {264 // Skip over CIEs.265 p += cfiLength;266 } else {267 // Process FDE to see if it covers pc.268 pint_t nextCFI = p + cfiLength;269 uint32_t ciePointer = addressSpace.get32(p);270 pint_t cieStart = p - ciePointer;271 // Validate pointer to CIE is within section.272 if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) {273 if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) {274 p += 4;275 // Parse pc begin and range.276 pint_t pcStart =277 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);278 pint_t pcRange = addressSpace.getEncodedP(279 p, nextCFI, cieInfo->pointerEncoding & 0x0F);280 // Test if pc is within the function this FDE covers.281 if ((pcStart <= pc) && (pc < pcStart + pcRange)) {282 // parse rest of info283 fdeInfo->lsda = 0;284 // check for augmentation length285 if (cieInfo->fdesHaveAugmentationData) {286 pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);287 pint_t endOfAug = p + augLen;288 if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {289 // Peek at value (without indirection). Zero means no LSDA.290 pint_t lsdaStart = p;291 if (addressSpace.getEncodedP(292 p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) {293 // Reset pointer and re-parse LSDA address.294 p = lsdaStart;295 fdeInfo->lsda = addressSpace296 .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);297 }298 }299 p = endOfAug;300 }301 fdeInfo->fdeStart = currentCFI;302 fdeInfo->fdeLength = nextCFI - currentCFI;303 fdeInfo->fdeInstructions = p;304 fdeInfo->pcStart = pcStart;305 fdeInfo->pcEnd = pcStart + pcRange;306 return true;307 } else {308 // pc is not in begin/range, skip this FDE309 }310 } else {311 // Malformed CIE, now augmentation describing pc range encoding.312 }313 } else {314 // malformed FDE. CIE is bad315 }316 p = nextCFI;317 }318 }319 return false;320}321 322/// Extract info from a CIE323template <typename A>324const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,325 CIE_Info *cieInfo) {326 cieInfo->pointerEncoding = 0;327 cieInfo->lsdaEncoding = DW_EH_PE_omit;328 cieInfo->personalityEncoding = 0;329 cieInfo->personalityOffsetInCIE = 0;330 cieInfo->personality = 0;331 cieInfo->codeAlignFactor = 0;332 cieInfo->dataAlignFactor = 0;333 cieInfo->isSignalFrame = false;334 cieInfo->fdesHaveAugmentationData = false;335#if defined(_LIBUNWIND_TARGET_AARCH64)336 cieInfo->addressesSignedWithBKey = false;337 cieInfo->mteTaggedFrame = false;338#endif339 cieInfo->cieStart = cie;340 pint_t p = cie;341 pint_t cieLength = (pint_t)addressSpace.get32(p);342 p += 4;343 pint_t cieContentEnd = p + cieLength;344 if (cieLength == 0xffffffff) {345 // 0xffffffff means length is really next 8 bytes346 cieLength = (pint_t)addressSpace.get64(p);347 p += 8;348 cieContentEnd = p + cieLength;349 }350 if (cieLength == 0)351 return NULL;352 // CIE ID is always 0353 if (addressSpace.get32(p) != 0)354 return "CIE ID is not zero";355 p += 4;356 // Version is always 1 or 3357 uint8_t version = addressSpace.get8(p);358 if ((version != 1) && (version != 3))359 return "CIE version is not 1 or 3";360 ++p;361 // save start of augmentation string and find end362 pint_t strStart = p;363 while (addressSpace.get8(p) != 0)364 ++p;365 ++p;366 // parse code alignment factor367 cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd);368 // parse data alignment factor369 cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd);370 // parse return address register371 uint64_t raReg = (version == 1) ? addressSpace.get8(p++)372 : addressSpace.getULEB128(p, cieContentEnd);373 assert(raReg < 255 && "return address register too large");374 cieInfo->returnAddressRegister = (uint8_t)raReg;375 // parse augmentation data based on augmentation string376 const char *result = NULL;377 pint_t resultAddr = 0;378 if (addressSpace.get8(strStart) == 'z') {379 // parse augmentation data length380 addressSpace.getULEB128(p, cieContentEnd);381 for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) {382 switch (addressSpace.get8(s)) {383 case 'z':384 cieInfo->fdesHaveAugmentationData = true;385 break;386 case 'P': {387 cieInfo->personalityEncoding = addressSpace.get8(p);388 ++p;389 cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);390 pint_t personality = addressSpace.getEncodedP(391 p, cieContentEnd, cieInfo->personalityEncoding,392 /*datarelBase=*/0, &resultAddr);393#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)394 if (personality) {395 // The GOT for the personality function was signed address396 // authenticated. Manually re-sign with the CIE_Info::personality397 // schema. If we could guarantee the encoding of the personality we398 // could avoid this by simply giving resultAddr the correct ptrauth399 // schema and performing an assignment.400#if defined(__arm64e__)401 const auto oldDiscriminator = resultAddr;402#else403 const auto oldDiscriminator = ptrauth_blend_discriminator(404 (void *)resultAddr, __ptrauth_unwind_pauthtest_personality_disc);405#endif406 const auto discriminator = ptrauth_blend_discriminator(407 &cieInfo->personality,408 __ptrauth_unwind_cie_info_personality_disc);409 void *signedPtr = ptrauth_auth_and_resign(410 (void *)personality, ptrauth_key_function_pointer,411 oldDiscriminator, ptrauth_key_function_pointer, discriminator);412 personality = (pint_t)signedPtr;413 }414#endif415 // We use memmove to set the CIE personality as we have already416 // re-signed the pointer to the correct schema.417 memmove((void *)&cieInfo->personality, (void *)&personality,418 sizeof(personality));419 break;420 }421 case 'L':422 cieInfo->lsdaEncoding = addressSpace.get8(p);423 ++p;424 break;425 case 'R':426 cieInfo->pointerEncoding = addressSpace.get8(p);427 ++p;428 break;429 case 'S':430 cieInfo->isSignalFrame = true;431 break;432#if defined(_LIBUNWIND_TARGET_AARCH64)433 case 'B':434 cieInfo->addressesSignedWithBKey = true;435 break;436 case 'G':437 cieInfo->mteTaggedFrame = true;438 break;439#endif440 default:441 // ignore unknown letters442 break;443 }444 }445 }446 cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;447 cieInfo->cieInstructions = p;448 return result;449}450 451 452/// "run" the DWARF instructions and create the abstract PrologInfo for an FDE453template <typename A>454bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,455 const FDE_Info &fdeInfo,456 const CIE_Info &cieInfo, pint_t upToPC,457 int arch, PrologInfo *results) {458 // Alloca is used for the allocation of the rememberStack entries. It removes459 // the dependency on new/malloc but the below for loop can not be refactored460 // into functions. Entry could be saved during the processing of a CIE and461 // restored by an FDE.462 RememberStack rememberStack;463 464 struct ParseInfo {465 pint_t instructions;466 pint_t instructionsEnd;467 pint_t pcoffset;468 };469 470 ParseInfo parseInfoArray[] = {471 {cieInfo.cieInstructions, cieInfo.cieStart + cieInfo.cieLength,472 (pint_t)(-1)},473 {fdeInfo.fdeInstructions, fdeInfo.fdeStart + fdeInfo.fdeLength,474 upToPC - fdeInfo.pcStart}};475 476 for (const auto &info : parseInfoArray) {477 pint_t p = info.instructions;478 pint_t instructionsEnd = info.instructionsEnd;479 pint_t pcoffset = info.pcoffset;480 pint_t codeOffset = 0;481 482 // initialState initialized as registers in results are modified. Use483 // PrologInfo accessor functions to avoid reading uninitialized data.484 PrologInfo initialState(PrologInfo::InitializeTime::kLazy);485 486 _LIBUNWIND_TRACE_DWARF("parseFDEInstructions(instructions=0x%0" PRIx64487 ")\n",488 static_cast<uint64_t>(instructionsEnd));489 490 // see DWARF Spec, section 6.4.2 for details on unwind opcodes491 while ((p < instructionsEnd) && (codeOffset < pcoffset)) {492 uint64_t reg;493 uint64_t reg2;494 int64_t offset;495 uint64_t length;496 uint8_t opcode = addressSpace.get8(p);497 uint8_t operand;498 499 ++p;500 switch (opcode) {501 case DW_CFA_nop:502 _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n");503 break;504 case DW_CFA_set_loc:505 codeOffset = addressSpace.getEncodedP(p, instructionsEnd,506 cieInfo.pointerEncoding);507 _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n");508 break;509 case DW_CFA_advance_loc1:510 codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);511 p += 1;512 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",513 static_cast<uint64_t>(codeOffset));514 break;515 case DW_CFA_advance_loc2:516 codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);517 p += 2;518 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",519 static_cast<uint64_t>(codeOffset));520 break;521 case DW_CFA_advance_loc4:522 codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);523 p += 4;524 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",525 static_cast<uint64_t>(codeOffset));526 break;527 case DW_CFA_offset_extended:528 reg = addressSpace.getULEB128(p, instructionsEnd);529 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *530 cieInfo.dataAlignFactor;531 if (reg > kMaxRegisterNumber) {532 _LIBUNWIND_LOG0(533 "malformed DW_CFA_offset_extended DWARF unwind, reg too big");534 return false;535 }536 results->setRegister(reg, kRegisterInCFA, offset, initialState);537 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", "538 "offset=%" PRId64 ")\n",539 reg, offset);540 break;541 case DW_CFA_restore_extended:542 reg = addressSpace.getULEB128(p, instructionsEnd);543 if (reg > kMaxRegisterNumber) {544 _LIBUNWIND_LOG0(545 "malformed DW_CFA_restore_extended DWARF unwind, reg too big");546 return false;547 }548 results->restoreRegisterToInitialState(reg, initialState);549 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n",550 reg);551 break;552 case DW_CFA_undefined:553 reg = addressSpace.getULEB128(p, instructionsEnd);554 if (reg > kMaxRegisterNumber) {555 _LIBUNWIND_LOG0(556 "malformed DW_CFA_undefined DWARF unwind, reg too big");557 return false;558 }559 results->setRegisterLocation(reg, kRegisterUndefined, initialState);560 _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);561 break;562 case DW_CFA_same_value:563 reg = addressSpace.getULEB128(p, instructionsEnd);564 if (reg > kMaxRegisterNumber) {565 _LIBUNWIND_LOG0(566 "malformed DW_CFA_same_value DWARF unwind, reg too big");567 return false;568 }569 // <rdar://problem/8456377> DW_CFA_same_value unsupported570 // "same value" means register was stored in frame, but its current571 // value has not changed, so no need to restore from frame.572 // We model this as if the register was never saved.573 results->setRegisterLocation(reg, kRegisterUnused, initialState);574 _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);575 break;576 case DW_CFA_register:577 reg = addressSpace.getULEB128(p, instructionsEnd);578 reg2 = addressSpace.getULEB128(p, instructionsEnd);579 if (reg > kMaxRegisterNumber) {580 _LIBUNWIND_LOG0(581 "malformed DW_CFA_register DWARF unwind, reg too big");582 return false;583 }584 if (reg2 > kMaxRegisterNumber) {585 _LIBUNWIND_LOG0(586 "malformed DW_CFA_register DWARF unwind, reg2 too big");587 return false;588 }589 results->setRegister(reg, kRegisterInRegister, (int64_t)reg2,590 initialState);591 _LIBUNWIND_TRACE_DWARF(592 "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2);593 break;594 case DW_CFA_remember_state: {595 // Avoid operator new because that would be an upward dependency.596 // Avoid malloc because it needs heap allocation.597 PrologInfoStackEntry *entry =598 (PrologInfoStackEntry *)_LIBUNWIND_REMEMBER_ALLOC(599 sizeof(PrologInfoStackEntry));600 if (entry != NULL) {601 entry->next = rememberStack.entry;602 entry->info = *results;603 rememberStack.entry = entry;604 } else {605 return false;606 }607 _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n");608 break;609 }610 case DW_CFA_restore_state:611 if (rememberStack.entry != NULL) {612 PrologInfoStackEntry *top = rememberStack.entry;613 *results = top->info;614 rememberStack.entry = top->next;615 _LIBUNWIND_REMEMBER_FREE(top);616 } else {617 return false;618 }619 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n");620 break;621 case DW_CFA_def_cfa:622 reg = addressSpace.getULEB128(p, instructionsEnd);623 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);624 if (reg > kMaxRegisterNumber) {625 _LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big");626 return false;627 }628 results->cfaRegister = (uint32_t)reg;629 results->cfaRegisterOffset = (int32_t)offset;630 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64631 ")\n",632 reg, offset);633 break;634 case DW_CFA_def_cfa_register:635 reg = addressSpace.getULEB128(p, instructionsEnd);636 if (reg > kMaxRegisterNumber) {637 _LIBUNWIND_LOG0(638 "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big");639 return false;640 }641 results->cfaRegister = (uint32_t)reg;642 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);643 break;644 case DW_CFA_def_cfa_offset:645 results->cfaRegisterOffset =646 (int32_t)addressSpace.getULEB128(p, instructionsEnd);647 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n",648 results->cfaRegisterOffset);649 break;650 case DW_CFA_def_cfa_expression:651 results->cfaRegister = 0;652 results->cfaExpression = (int64_t)p;653 length = addressSpace.getULEB128(p, instructionsEnd);654 assert(length < static_cast<pint_t>(~0) && "pointer overflow");655 p += static_cast<pint_t>(length);656 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64657 ", length=%" PRIu64 ")\n",658 results->cfaExpression, length);659 break;660 case DW_CFA_expression:661 reg = addressSpace.getULEB128(p, instructionsEnd);662 if (reg > kMaxRegisterNumber) {663 _LIBUNWIND_LOG0(664 "malformed DW_CFA_expression DWARF unwind, reg too big");665 return false;666 }667 results->setRegister(reg, kRegisterAtExpression, (int64_t)p,668 initialState);669 length = addressSpace.getULEB128(p, instructionsEnd);670 assert(length < static_cast<pint_t>(~0) && "pointer overflow");671 p += static_cast<pint_t>(length);672 _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", "673 "expression=0x%" PRIx64 ", "674 "length=%" PRIu64 ")\n",675 reg, results->savedRegisters[reg].value, length);676 break;677 case DW_CFA_offset_extended_sf:678 reg = addressSpace.getULEB128(p, instructionsEnd);679 if (reg > kMaxRegisterNumber) {680 _LIBUNWIND_LOG0(681 "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big");682 return false;683 }684 offset = addressSpace.getSLEB128(p, instructionsEnd) *685 cieInfo.dataAlignFactor;686 results->setRegister(reg, kRegisterInCFA, offset, initialState);687 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", "688 "offset=%" PRId64 ")\n",689 reg, offset);690 break;691 case DW_CFA_def_cfa_sf:692 reg = addressSpace.getULEB128(p, instructionsEnd);693 offset = addressSpace.getSLEB128(p, instructionsEnd) *694 cieInfo.dataAlignFactor;695 if (reg > kMaxRegisterNumber) {696 _LIBUNWIND_LOG0(697 "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big");698 return false;699 }700 results->cfaRegister = (uint32_t)reg;701 results->cfaRegisterOffset = (int32_t)offset;702 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", "703 "offset=%" PRId64 ")\n",704 reg, offset);705 break;706 case DW_CFA_def_cfa_offset_sf:707 results->cfaRegisterOffset =708 (int32_t)(addressSpace.getSLEB128(p, instructionsEnd) *709 cieInfo.dataAlignFactor);710 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n",711 results->cfaRegisterOffset);712 break;713 case DW_CFA_val_offset:714 reg = addressSpace.getULEB128(p, instructionsEnd);715 if (reg > kMaxRegisterNumber) {716 _LIBUNWIND_LOG(717 "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64718 ") out of range\n",719 reg);720 return false;721 }722 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *723 cieInfo.dataAlignFactor;724 results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);725 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "726 "offset=%" PRId64 "\n",727 reg, offset);728 break;729 case DW_CFA_val_offset_sf:730 reg = addressSpace.getULEB128(p, instructionsEnd);731 if (reg > kMaxRegisterNumber) {732 _LIBUNWIND_LOG0(733 "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big");734 return false;735 }736 offset = addressSpace.getSLEB128(p, instructionsEnd) *737 cieInfo.dataAlignFactor;738 results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);739 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "740 "offset=%" PRId64 "\n",741 reg, offset);742 break;743 case DW_CFA_val_expression:744 reg = addressSpace.getULEB128(p, instructionsEnd);745 if (reg > kMaxRegisterNumber) {746 _LIBUNWIND_LOG0(747 "malformed DW_CFA_val_expression DWARF unwind, reg too big");748 return false;749 }750 results->setRegister(reg, kRegisterIsExpression, (int64_t)p,751 initialState);752 length = addressSpace.getULEB128(p, instructionsEnd);753 assert(length < static_cast<pint_t>(~0) && "pointer overflow");754 p += static_cast<pint_t>(length);755 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "756 "expression=0x%" PRIx64 ", length=%" PRIu64757 ")\n",758 reg, results->savedRegisters[reg].value, length);759 break;760 case DW_CFA_GNU_args_size:761 length = addressSpace.getULEB128(p, instructionsEnd);762 results->spExtraArgSize = (uint32_t)length;763 _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);764 break;765 case DW_CFA_GNU_negative_offset_extended:766 reg = addressSpace.getULEB128(p, instructionsEnd);767 if (reg > kMaxRegisterNumber) {768 _LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF "769 "unwind, reg too big");770 return false;771 }772 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *773 cieInfo.dataAlignFactor;774 results->setRegister(reg, kRegisterInCFA, -offset, initialState);775 _LIBUNWIND_TRACE_DWARF(776 "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);777 break;778 779#if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC) || \780 defined(_LIBUNWIND_TARGET_SPARC64)781 // The same constant is used to represent different instructions on782 // AArch64 (negate_ra_state) and SPARC (window_save).783 static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save,784 "uses the same constant");785 case DW_CFA_AARCH64_negate_ra_state:786 switch (arch) {787#if defined(_LIBUNWIND_TARGET_AARCH64)788 case REGISTERS_ARM64: {789 int64_t value =790 results->savedRegisters[UNW_AARCH64_RA_SIGN_STATE].value ^ 0x1;791 results->setRegisterValue(UNW_AARCH64_RA_SIGN_STATE, value,792 initialState);793 _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n");794 } break;795#endif796 797#if defined(_LIBUNWIND_TARGET_SPARC)798 // case DW_CFA_GNU_window_save:799 case REGISTERS_SPARC:800 _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n");801 for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) {802 results->setRegister(reg, kRegisterInRegister,803 ((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0,804 initialState);805 }806 807 for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {808 results->setRegister(reg, kRegisterInCFA,809 ((int64_t)reg - UNW_SPARC_L0) * 4,810 initialState);811 }812 break;813#endif814 815#if defined(_LIBUNWIND_TARGET_SPARC64)816 // case DW_CFA_GNU_window_save:817 case REGISTERS_SPARC64:818 // Don't save %o0-%o7 on sparc64.819 // https://reviews.llvm.org/D32450#736405820 821 for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {822 if (reg == UNW_SPARC_I7)823 results->setRegister(824 reg, kRegisterInCFADecrypt,825 static_cast<int64_t>((reg - UNW_SPARC_L0) * sizeof(pint_t)),826 initialState);827 else828 results->setRegister(829 reg, kRegisterInCFA,830 static_cast<int64_t>((reg - UNW_SPARC_L0) * sizeof(pint_t)),831 initialState);832 }833 _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save\n");834 break;835#endif836 }837 break;838 839#if defined(_LIBUNWIND_TARGET_AARCH64)840 case DW_CFA_AARCH64_negate_ra_state_with_pc: {841 int64_t value =842 results->savedRegisters[UNW_AARCH64_RA_SIGN_STATE].value ^ 0x3;843 results->setRegisterValue(UNW_AARCH64_RA_SIGN_STATE, value,844 initialState);845 // When using Feat_PAuthLR, the PC value needs to be captured so that846 // during unwinding, the correct PC value is used for re-authentication.847 // It is assumed that the CFI is placed before the signing instruction.848 results->ptrAuthDiversifier = fdeInfo.pcStart + codeOffset;849 _LIBUNWIND_TRACE_DWARF(850 "DW_CFA_AARCH64_negate_ra_state_with_pc(pc=0x%" PRIx64 ")\n",851 static_cast<uint64_t>(results->ptrAuthDiversifier));852 } break;853#endif854 855#else856 (void)arch;857#endif858 859 default:860 operand = opcode & 0x3F;861 switch (opcode & 0xC0) {862 case DW_CFA_offset:863 reg = operand;864 if (reg > kMaxRegisterNumber) {865 _LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64866 ") out of range",867 reg);868 return false;869 }870 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *871 cieInfo.dataAlignFactor;872 results->setRegister(reg, kRegisterInCFA, offset, initialState);873 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",874 operand, offset);875 break;876 case DW_CFA_advance_loc:877 codeOffset += operand * cieInfo.codeAlignFactor;878 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",879 static_cast<uint64_t>(codeOffset));880 break;881 case DW_CFA_restore:882 reg = operand;883 if (reg > kMaxRegisterNumber) {884 _LIBUNWIND_LOG(885 "malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64886 ") out of range",887 reg);888 return false;889 }890 results->restoreRegisterToInitialState(reg, initialState);891 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",892 static_cast<uint64_t>(operand));893 break;894 default:895 _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);896 return false;897 }898 }899 }900 }901 return true;902}903 904} // namespace libunwind905 906#endif // __DWARF_PARSER_HPP__907