Path: blob/main/system/lib/libunwind/src/DwarfParser.hpp
6178 views
//===----------------------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//7// Parses DWARF CFIs (FDEs and CIEs).8//9//===----------------------------------------------------------------------===//1011#ifndef __DWARF_PARSER_HPP__12#define __DWARF_PARSER_HPP__1314#include <inttypes.h>15#include <stdint.h>16#include <stdio.h>17#include <stdlib.h>1819#include "libunwind.h"20#include "dwarf2.h"21#include "Registers.hpp"2223#include "config.h"2425namespace libunwind {2627/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.28/// See DWARF Spec for details:29/// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html30///31template <typename A>32class CFI_Parser {33public:34typedef typename A::pint_t pint_t;3536/// Information encoded in a CIE (Common Information Entry)37struct CIE_Info {38pint_t cieStart;39pint_t cieLength;40pint_t cieInstructions;41uint8_t pointerEncoding;42uint8_t lsdaEncoding;43uint8_t personalityEncoding;44uint8_t personalityOffsetInCIE;45pint_t personality;46uint32_t codeAlignFactor;47int dataAlignFactor;48bool isSignalFrame;49bool fdesHaveAugmentationData;50uint8_t returnAddressRegister;51#if defined(_LIBUNWIND_TARGET_AARCH64)52bool addressesSignedWithBKey;53bool mteTaggedFrame;54#endif55};5657/// Information about an FDE (Frame Description Entry)58struct FDE_Info {59pint_t fdeStart;60pint_t fdeLength;61pint_t fdeInstructions;62pint_t pcStart;63pint_t pcEnd;64pint_t lsda;65};6667enum {68kMaxRegisterNumber = _LIBUNWIND_HIGHEST_DWARF_REGISTER69};70enum RegisterSavedWhere {71kRegisterUnused,72kRegisterUndefined,73kRegisterInCFA,74kRegisterInCFADecrypt, // sparc64 specific75kRegisterOffsetFromCFA,76kRegisterInRegister,77kRegisterAtExpression,78kRegisterIsExpression79};80struct RegisterLocation {81RegisterSavedWhere location;82bool initialStateSaved;83int64_t value;84};85/// Information about a frame layout and registers saved determined86/// by "running" the DWARF FDE "instructions"87struct PrologInfo {88uint32_t cfaRegister;89int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset90int64_t cfaExpression; // CFA = expression91uint32_t spExtraArgSize;92RegisterLocation savedRegisters[kMaxRegisterNumber + 1];93#if defined(_LIBUNWIND_TARGET_AARCH64)94pint_t ptrAuthDiversifier;95#endif96enum class InitializeTime { kLazy, kNormal };9798// When saving registers, this data structure is lazily initialized.99PrologInfo(InitializeTime IT = InitializeTime::kNormal) {100if (IT == InitializeTime::kNormal)101memset(this, 0, sizeof(*this));102}103void checkSaveRegister(uint64_t reg, PrologInfo &initialState) {104if (!savedRegisters[reg].initialStateSaved) {105initialState.savedRegisters[reg] = savedRegisters[reg];106savedRegisters[reg].initialStateSaved = true;107}108}109void setRegister(uint64_t reg, RegisterSavedWhere newLocation,110int64_t newValue, PrologInfo &initialState) {111checkSaveRegister(reg, initialState);112savedRegisters[reg].location = newLocation;113savedRegisters[reg].value = newValue;114}115void setRegisterLocation(uint64_t reg, RegisterSavedWhere newLocation,116PrologInfo &initialState) {117checkSaveRegister(reg, initialState);118savedRegisters[reg].location = newLocation;119}120void setRegisterValue(uint64_t reg, int64_t newValue,121PrologInfo &initialState) {122checkSaveRegister(reg, initialState);123savedRegisters[reg].value = newValue;124}125void restoreRegisterToInitialState(uint64_t reg, PrologInfo &initialState) {126if (savedRegisters[reg].initialStateSaved)127savedRegisters[reg] = initialState.savedRegisters[reg];128// else the register still holds its initial state129}130};131132struct PrologInfoStackEntry {133PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i)134: next(n), info(i) {}135PrologInfoStackEntry *next;136PrologInfo info;137};138139struct RememberStack {140PrologInfoStackEntry *entry;141RememberStack() : entry(nullptr) {}142~RememberStack() {143#if defined(_LIBUNWIND_REMEMBER_CLEANUP_NEEDED)144// Clean up rememberStack. Even in the case where every145// DW_CFA_remember_state is paired with a DW_CFA_restore_state,146// parseInstructions can skip restore opcodes if it reaches the target PC147// and stops interpreting, so we have to make sure we don't leak memory.148while (entry) {149PrologInfoStackEntry *next = entry->next;150_LIBUNWIND_REMEMBER_FREE(entry);151entry = next;152}153#endif154}155};156157static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,158size_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,159CIE_Info *cieInfo);160static const char *decodeFDE(A &addressSpace, pint_t fdeStart,161FDE_Info *fdeInfo, CIE_Info *cieInfo,162bool useCIEInfo = false);163static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,164const CIE_Info &cieInfo, pint_t upToPC,165int arch, PrologInfo *results);166167static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);168};169170/// Parse a FDE into a CIE_Info and an FDE_Info. If useCIEInfo is171/// true, treat cieInfo as already-parsed CIE_Info (whose start offset172/// must match the one specified by the FDE) rather than parsing the173/// one indicated within the FDE.174template <typename A>175const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,176FDE_Info *fdeInfo, CIE_Info *cieInfo,177bool useCIEInfo) {178pint_t p = fdeStart;179pint_t cfiLength = (pint_t)addressSpace.get32(p);180p += 4;181if (cfiLength == 0xffffffff) {182// 0xffffffff means length is really next 8 bytes183cfiLength = (pint_t)addressSpace.get64(p);184p += 8;185}186if (cfiLength == 0)187return "FDE has zero length"; // zero terminator188uint32_t ciePointer = addressSpace.get32(p);189if (ciePointer == 0)190return "FDE is really a CIE"; // this is a CIE not an FDE191pint_t nextCFI = p + cfiLength;192pint_t cieStart = p - ciePointer;193if (useCIEInfo) {194if (cieInfo->cieStart != cieStart)195return "CIE start does not match";196} else {197const char *err = parseCIE(addressSpace, cieStart, cieInfo);198if (err != NULL)199return err;200}201p += 4;202// Parse pc begin and range.203pint_t pcStart =204addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);205pint_t pcRange =206addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);207// Parse rest of info.208fdeInfo->lsda = 0;209// Check for augmentation length.210if (cieInfo->fdesHaveAugmentationData) {211pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);212pint_t endOfAug = p + augLen;213if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {214// Peek at value (without indirection). Zero means no LSDA.215pint_t lsdaStart = p;216if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) !=2170) {218// Reset pointer and re-parse LSDA address.219p = lsdaStart;220fdeInfo->lsda =221addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);222}223}224p = endOfAug;225}226fdeInfo->fdeStart = fdeStart;227fdeInfo->fdeLength = nextCFI - fdeStart;228fdeInfo->fdeInstructions = p;229fdeInfo->pcStart = pcStart;230fdeInfo->pcEnd = pcStart + pcRange;231return NULL; // success232}233234/// Scan an eh_frame section to find an FDE for a pc235template <typename A>236bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,237size_t sectionLength, pint_t fdeHint,238FDE_Info *fdeInfo, CIE_Info *cieInfo) {239//fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);240pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;241const pint_t ehSectionEnd = (sectionLength == SIZE_MAX)242? static_cast<pint_t>(-1)243: (ehSectionStart + sectionLength);244while (p < ehSectionEnd) {245pint_t currentCFI = p;246//fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);247pint_t cfiLength = addressSpace.get32(p);248p += 4;249if (cfiLength == 0xffffffff) {250// 0xffffffff means length is really next 8 bytes251cfiLength = (pint_t)addressSpace.get64(p);252p += 8;253}254if (cfiLength == 0)255return false; // zero terminator256uint32_t id = addressSpace.get32(p);257if (id == 0) {258// Skip over CIEs.259p += cfiLength;260} else {261// Process FDE to see if it covers pc.262pint_t nextCFI = p + cfiLength;263uint32_t ciePointer = addressSpace.get32(p);264pint_t cieStart = p - ciePointer;265// Validate pointer to CIE is within section.266if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) {267if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) {268p += 4;269// Parse pc begin and range.270pint_t pcStart =271addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);272pint_t pcRange = addressSpace.getEncodedP(273p, nextCFI, cieInfo->pointerEncoding & 0x0F);274// Test if pc is within the function this FDE covers.275if ((pcStart < pc) && (pc <= pcStart + pcRange)) {276// parse rest of info277fdeInfo->lsda = 0;278// check for augmentation length279if (cieInfo->fdesHaveAugmentationData) {280pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);281pint_t endOfAug = p + augLen;282if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {283// Peek at value (without indirection). Zero means no LSDA.284pint_t lsdaStart = p;285if (addressSpace.getEncodedP(286p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) {287// Reset pointer and re-parse LSDA address.288p = lsdaStart;289fdeInfo->lsda = addressSpace290.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);291}292}293p = endOfAug;294}295fdeInfo->fdeStart = currentCFI;296fdeInfo->fdeLength = nextCFI - currentCFI;297fdeInfo->fdeInstructions = p;298fdeInfo->pcStart = pcStart;299fdeInfo->pcEnd = pcStart + pcRange;300return true;301} else {302// pc is not in begin/range, skip this FDE303}304} else {305// Malformed CIE, now augmentation describing pc range encoding.306}307} else {308// malformed FDE. CIE is bad309}310p = nextCFI;311}312}313return false;314}315316/// Extract info from a CIE317template <typename A>318const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,319CIE_Info *cieInfo) {320cieInfo->pointerEncoding = 0;321cieInfo->lsdaEncoding = DW_EH_PE_omit;322cieInfo->personalityEncoding = 0;323cieInfo->personalityOffsetInCIE = 0;324cieInfo->personality = 0;325cieInfo->codeAlignFactor = 0;326cieInfo->dataAlignFactor = 0;327cieInfo->isSignalFrame = false;328cieInfo->fdesHaveAugmentationData = false;329#if defined(_LIBUNWIND_TARGET_AARCH64)330cieInfo->addressesSignedWithBKey = false;331cieInfo->mteTaggedFrame = false;332#endif333cieInfo->cieStart = cie;334pint_t p = cie;335pint_t cieLength = (pint_t)addressSpace.get32(p);336p += 4;337pint_t cieContentEnd = p + cieLength;338if (cieLength == 0xffffffff) {339// 0xffffffff means length is really next 8 bytes340cieLength = (pint_t)addressSpace.get64(p);341p += 8;342cieContentEnd = p + cieLength;343}344if (cieLength == 0)345return NULL;346// CIE ID is always 0347if (addressSpace.get32(p) != 0)348return "CIE ID is not zero";349p += 4;350// Version is always 1 or 3351uint8_t version = addressSpace.get8(p);352if ((version != 1) && (version != 3))353return "CIE version is not 1 or 3";354++p;355// save start of augmentation string and find end356pint_t strStart = p;357while (addressSpace.get8(p) != 0)358++p;359++p;360// parse code alignment factor361cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd);362// parse data alignment factor363cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd);364// parse return address register365uint64_t raReg = (version == 1) ? addressSpace.get8(p++)366: addressSpace.getULEB128(p, cieContentEnd);367assert(raReg < 255 && "return address register too large");368cieInfo->returnAddressRegister = (uint8_t)raReg;369// parse augmentation data based on augmentation string370const char *result = NULL;371if (addressSpace.get8(strStart) == 'z') {372// parse augmentation data length373addressSpace.getULEB128(p, cieContentEnd);374for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) {375switch (addressSpace.get8(s)) {376case 'z':377cieInfo->fdesHaveAugmentationData = true;378break;379case 'P':380cieInfo->personalityEncoding = addressSpace.get8(p);381++p;382cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);383cieInfo->personality = addressSpace384.getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);385break;386case 'L':387cieInfo->lsdaEncoding = addressSpace.get8(p);388++p;389break;390case 'R':391cieInfo->pointerEncoding = addressSpace.get8(p);392++p;393break;394case 'S':395cieInfo->isSignalFrame = true;396break;397#if defined(_LIBUNWIND_TARGET_AARCH64)398case 'B':399cieInfo->addressesSignedWithBKey = true;400break;401case 'G':402cieInfo->mteTaggedFrame = true;403break;404#endif405default:406// ignore unknown letters407break;408}409}410}411cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;412cieInfo->cieInstructions = p;413return result;414}415416417/// "run" the DWARF instructions and create the abstract PrologInfo for an FDE418template <typename A>419bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,420const FDE_Info &fdeInfo,421const CIE_Info &cieInfo, pint_t upToPC,422int arch, PrologInfo *results) {423// Alloca is used for the allocation of the rememberStack entries. It removes424// the dependency on new/malloc but the below for loop can not be refactored425// into functions. Entry could be saved during the processing of a CIE and426// restored by an FDE.427RememberStack rememberStack;428429struct ParseInfo {430pint_t instructions;431pint_t instructionsEnd;432pint_t pcoffset;433};434435ParseInfo parseInfoArray[] = {436{cieInfo.cieInstructions, cieInfo.cieStart + cieInfo.cieLength,437(pint_t)(-1)},438{fdeInfo.fdeInstructions, fdeInfo.fdeStart + fdeInfo.fdeLength,439upToPC - fdeInfo.pcStart}};440441for (const auto &info : parseInfoArray) {442pint_t p = info.instructions;443pint_t instructionsEnd = info.instructionsEnd;444pint_t pcoffset = info.pcoffset;445pint_t codeOffset = 0;446447// initialState initialized as registers in results are modified. Use448// PrologInfo accessor functions to avoid reading uninitialized data.449PrologInfo initialState(PrologInfo::InitializeTime::kLazy);450451_LIBUNWIND_TRACE_DWARF("parseFDEInstructions(instructions=0x%0" PRIx64452")\n",453static_cast<uint64_t>(instructionsEnd));454455// see DWARF Spec, section 6.4.2 for details on unwind opcodes456while ((p < instructionsEnd) && (codeOffset < pcoffset)) {457uint64_t reg;458uint64_t reg2;459int64_t offset;460uint64_t length;461uint8_t opcode = addressSpace.get8(p);462uint8_t operand;463464++p;465switch (opcode) {466case DW_CFA_nop:467_LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n");468break;469case DW_CFA_set_loc:470codeOffset = addressSpace.getEncodedP(p, instructionsEnd,471cieInfo.pointerEncoding);472_LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n");473break;474case DW_CFA_advance_loc1:475codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);476p += 1;477_LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",478static_cast<uint64_t>(codeOffset));479break;480case DW_CFA_advance_loc2:481codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);482p += 2;483_LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",484static_cast<uint64_t>(codeOffset));485break;486case DW_CFA_advance_loc4:487codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);488p += 4;489_LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",490static_cast<uint64_t>(codeOffset));491break;492case DW_CFA_offset_extended:493reg = addressSpace.getULEB128(p, instructionsEnd);494offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *495cieInfo.dataAlignFactor;496if (reg > kMaxRegisterNumber) {497_LIBUNWIND_LOG0(498"malformed DW_CFA_offset_extended DWARF unwind, reg too big");499return false;500}501results->setRegister(reg, kRegisterInCFA, offset, initialState);502_LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", "503"offset=%" PRId64 ")\n",504reg, offset);505break;506case DW_CFA_restore_extended:507reg = addressSpace.getULEB128(p, instructionsEnd);508if (reg > kMaxRegisterNumber) {509_LIBUNWIND_LOG0(510"malformed DW_CFA_restore_extended DWARF unwind, reg too big");511return false;512}513results->restoreRegisterToInitialState(reg, initialState);514_LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n",515reg);516break;517case DW_CFA_undefined:518reg = addressSpace.getULEB128(p, instructionsEnd);519if (reg > kMaxRegisterNumber) {520_LIBUNWIND_LOG0(521"malformed DW_CFA_undefined DWARF unwind, reg too big");522return false;523}524results->setRegisterLocation(reg, kRegisterUndefined, initialState);525_LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);526break;527case DW_CFA_same_value:528reg = addressSpace.getULEB128(p, instructionsEnd);529if (reg > kMaxRegisterNumber) {530_LIBUNWIND_LOG0(531"malformed DW_CFA_same_value DWARF unwind, reg too big");532return false;533}534// <rdar://problem/8456377> DW_CFA_same_value unsupported535// "same value" means register was stored in frame, but its current536// value has not changed, so no need to restore from frame.537// We model this as if the register was never saved.538results->setRegisterLocation(reg, kRegisterUnused, initialState);539_LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);540break;541case DW_CFA_register:542reg = addressSpace.getULEB128(p, instructionsEnd);543reg2 = addressSpace.getULEB128(p, instructionsEnd);544if (reg > kMaxRegisterNumber) {545_LIBUNWIND_LOG0(546"malformed DW_CFA_register DWARF unwind, reg too big");547return false;548}549if (reg2 > kMaxRegisterNumber) {550_LIBUNWIND_LOG0(551"malformed DW_CFA_register DWARF unwind, reg2 too big");552return false;553}554results->setRegister(reg, kRegisterInRegister, (int64_t)reg2,555initialState);556_LIBUNWIND_TRACE_DWARF(557"DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2);558break;559case DW_CFA_remember_state: {560// Avoid operator new because that would be an upward dependency.561// Avoid malloc because it needs heap allocation.562PrologInfoStackEntry *entry =563(PrologInfoStackEntry *)_LIBUNWIND_REMEMBER_ALLOC(564sizeof(PrologInfoStackEntry));565if (entry != NULL) {566entry->next = rememberStack.entry;567entry->info = *results;568rememberStack.entry = entry;569} else {570return false;571}572_LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n");573break;574}575case DW_CFA_restore_state:576if (rememberStack.entry != NULL) {577PrologInfoStackEntry *top = rememberStack.entry;578*results = top->info;579rememberStack.entry = top->next;580_LIBUNWIND_REMEMBER_FREE(top);581} else {582return false;583}584_LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n");585break;586case DW_CFA_def_cfa:587reg = addressSpace.getULEB128(p, instructionsEnd);588offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);589if (reg > kMaxRegisterNumber) {590_LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big");591return false;592}593results->cfaRegister = (uint32_t)reg;594results->cfaRegisterOffset = (int32_t)offset;595_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64596")\n",597reg, offset);598break;599case DW_CFA_def_cfa_register:600reg = addressSpace.getULEB128(p, instructionsEnd);601if (reg > kMaxRegisterNumber) {602_LIBUNWIND_LOG0(603"malformed DW_CFA_def_cfa_register DWARF unwind, reg too big");604return false;605}606results->cfaRegister = (uint32_t)reg;607_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);608break;609case DW_CFA_def_cfa_offset:610results->cfaRegisterOffset =611(int32_t)addressSpace.getULEB128(p, instructionsEnd);612_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n",613results->cfaRegisterOffset);614break;615case DW_CFA_def_cfa_expression:616results->cfaRegister = 0;617results->cfaExpression = (int64_t)p;618length = addressSpace.getULEB128(p, instructionsEnd);619assert(length < static_cast<pint_t>(~0) && "pointer overflow");620p += static_cast<pint_t>(length);621_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64622", length=%" PRIu64 ")\n",623results->cfaExpression, length);624break;625case DW_CFA_expression:626reg = addressSpace.getULEB128(p, instructionsEnd);627if (reg > kMaxRegisterNumber) {628_LIBUNWIND_LOG0(629"malformed DW_CFA_expression DWARF unwind, reg too big");630return false;631}632results->setRegister(reg, kRegisterAtExpression, (int64_t)p,633initialState);634length = addressSpace.getULEB128(p, instructionsEnd);635assert(length < static_cast<pint_t>(~0) && "pointer overflow");636p += static_cast<pint_t>(length);637_LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", "638"expression=0x%" PRIx64 ", "639"length=%" PRIu64 ")\n",640reg, results->savedRegisters[reg].value, length);641break;642case DW_CFA_offset_extended_sf:643reg = addressSpace.getULEB128(p, instructionsEnd);644if (reg > kMaxRegisterNumber) {645_LIBUNWIND_LOG0(646"malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big");647return false;648}649offset = addressSpace.getSLEB128(p, instructionsEnd) *650cieInfo.dataAlignFactor;651results->setRegister(reg, kRegisterInCFA, offset, initialState);652_LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", "653"offset=%" PRId64 ")\n",654reg, offset);655break;656case DW_CFA_def_cfa_sf:657reg = addressSpace.getULEB128(p, instructionsEnd);658offset = addressSpace.getSLEB128(p, instructionsEnd) *659cieInfo.dataAlignFactor;660if (reg > kMaxRegisterNumber) {661_LIBUNWIND_LOG0(662"malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big");663return false;664}665results->cfaRegister = (uint32_t)reg;666results->cfaRegisterOffset = (int32_t)offset;667_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", "668"offset=%" PRId64 ")\n",669reg, offset);670break;671case DW_CFA_def_cfa_offset_sf:672results->cfaRegisterOffset =673(int32_t)(addressSpace.getSLEB128(p, instructionsEnd) *674cieInfo.dataAlignFactor);675_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n",676results->cfaRegisterOffset);677break;678case DW_CFA_val_offset:679reg = addressSpace.getULEB128(p, instructionsEnd);680if (reg > kMaxRegisterNumber) {681_LIBUNWIND_LOG(682"malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64683") out of range\n",684reg);685return false;686}687offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *688cieInfo.dataAlignFactor;689results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);690_LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "691"offset=%" PRId64 "\n",692reg, offset);693break;694case DW_CFA_val_offset_sf:695reg = addressSpace.getULEB128(p, instructionsEnd);696if (reg > kMaxRegisterNumber) {697_LIBUNWIND_LOG0(698"malformed DW_CFA_val_offset_sf DWARF unwind, reg too big");699return false;700}701offset = addressSpace.getSLEB128(p, instructionsEnd) *702cieInfo.dataAlignFactor;703results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);704_LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "705"offset=%" PRId64 "\n",706reg, offset);707break;708case DW_CFA_val_expression:709reg = addressSpace.getULEB128(p, instructionsEnd);710if (reg > kMaxRegisterNumber) {711_LIBUNWIND_LOG0(712"malformed DW_CFA_val_expression DWARF unwind, reg too big");713return false;714}715results->setRegister(reg, kRegisterIsExpression, (int64_t)p,716initialState);717length = addressSpace.getULEB128(p, instructionsEnd);718assert(length < static_cast<pint_t>(~0) && "pointer overflow");719p += static_cast<pint_t>(length);720_LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "721"expression=0x%" PRIx64 ", length=%" PRIu64722")\n",723reg, results->savedRegisters[reg].value, length);724break;725case DW_CFA_GNU_args_size:726length = addressSpace.getULEB128(p, instructionsEnd);727results->spExtraArgSize = (uint32_t)length;728_LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);729break;730case DW_CFA_GNU_negative_offset_extended:731reg = addressSpace.getULEB128(p, instructionsEnd);732if (reg > kMaxRegisterNumber) {733_LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF "734"unwind, reg too big");735return false;736}737offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *738cieInfo.dataAlignFactor;739results->setRegister(reg, kRegisterInCFA, -offset, initialState);740_LIBUNWIND_TRACE_DWARF(741"DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);742break;743744#if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC) || \745defined(_LIBUNWIND_TARGET_SPARC64)746// The same constant is used to represent different instructions on747// AArch64 (negate_ra_state) and SPARC (window_save).748static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save,749"uses the same constant");750case DW_CFA_AARCH64_negate_ra_state:751switch (arch) {752#if defined(_LIBUNWIND_TARGET_AARCH64)753case REGISTERS_ARM64: {754int64_t value =755results->savedRegisters[UNW_AARCH64_RA_SIGN_STATE].value ^ 0x1;756results->setRegisterValue(UNW_AARCH64_RA_SIGN_STATE, value,757initialState);758_LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n");759} break;760#endif761762#if defined(_LIBUNWIND_TARGET_SPARC)763// case DW_CFA_GNU_window_save:764case REGISTERS_SPARC:765_LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n");766for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) {767results->setRegister(reg, kRegisterInRegister,768((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0,769initialState);770}771772for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {773results->setRegister(reg, kRegisterInCFA,774((int64_t)reg - UNW_SPARC_L0) * 4,775initialState);776}777break;778#endif779780#if defined(_LIBUNWIND_TARGET_SPARC64)781// case DW_CFA_GNU_window_save:782case REGISTERS_SPARC64:783// Don't save %o0-%o7 on sparc64.784// https://reviews.llvm.org/D32450#736405785786for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {787if (reg == UNW_SPARC_I7)788results->setRegister(789reg, kRegisterInCFADecrypt,790static_cast<int64_t>((reg - UNW_SPARC_L0) * sizeof(pint_t)),791initialState);792else793results->setRegister(794reg, kRegisterInCFA,795static_cast<int64_t>((reg - UNW_SPARC_L0) * sizeof(pint_t)),796initialState);797}798_LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save\n");799break;800#endif801}802break;803804#if defined(_LIBUNWIND_TARGET_AARCH64)805case DW_CFA_AARCH64_negate_ra_state_with_pc: {806int64_t value =807results->savedRegisters[UNW_AARCH64_RA_SIGN_STATE].value ^ 0x3;808results->setRegisterValue(UNW_AARCH64_RA_SIGN_STATE, value,809initialState);810// When calculating the value of the PC, it is assumed that the CFI811// instruction is placed before the signing instruction, however it is812// placed after. Because of this, we need to take into account the CFI813// instruction is one instruction call later than expected, and reduce814// the PC value by 4 bytes to compensate.815results->ptrAuthDiversifier = fdeInfo.pcStart + codeOffset - 0x4;816_LIBUNWIND_TRACE_DWARF(817"DW_CFA_AARCH64_negate_ra_state_with_pc(pc=0x%" PRIx64 ")\n",818static_cast<uint64_t>(results->ptrAuthDiversifier));819} break;820#endif821822#else823(void)arch;824#endif825826default:827operand = opcode & 0x3F;828switch (opcode & 0xC0) {829case DW_CFA_offset:830reg = operand;831if (reg > kMaxRegisterNumber) {832_LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64833") out of range",834reg);835return false;836}837offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *838cieInfo.dataAlignFactor;839results->setRegister(reg, kRegisterInCFA, offset, initialState);840_LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",841operand, offset);842break;843case DW_CFA_advance_loc:844codeOffset += operand * cieInfo.codeAlignFactor;845_LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",846static_cast<uint64_t>(codeOffset));847break;848case DW_CFA_restore:849reg = operand;850if (reg > kMaxRegisterNumber) {851_LIBUNWIND_LOG(852"malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64853") out of range",854reg);855return false;856}857results->restoreRegisterToInitialState(reg, initialState);858_LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",859static_cast<uint64_t>(operand));860break;861default:862_LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);863return false;864}865}866}867}868return true;869}870871} // namespace libunwind872873#endif // __DWARF_PARSER_HPP__874875876