Path: blob/main/contrib/llvm-project/libunwind/src/DwarfParser.hpp
35154 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,72kRegisterInCFA,73kRegisterInCFADecrypt, // sparc64 specific74kRegisterOffsetFromCFA,75kRegisterInRegister,76kRegisterAtExpression,77kRegisterIsExpression78};79struct RegisterLocation {80RegisterSavedWhere location;81bool initialStateSaved;82int64_t value;83};84/// Information about a frame layout and registers saved determined85/// by "running" the DWARF FDE "instructions"86struct PrologInfo {87uint32_t cfaRegister;88int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset89int64_t cfaExpression; // CFA = expression90uint32_t spExtraArgSize;91RegisterLocation savedRegisters[kMaxRegisterNumber + 1];92enum class InitializeTime { kLazy, kNormal };9394// When saving registers, this data structure is lazily initialized.95PrologInfo(InitializeTime IT = InitializeTime::kNormal) {96if (IT == InitializeTime::kNormal)97memset(this, 0, sizeof(*this));98}99void checkSaveRegister(uint64_t reg, PrologInfo &initialState) {100if (!savedRegisters[reg].initialStateSaved) {101initialState.savedRegisters[reg] = savedRegisters[reg];102savedRegisters[reg].initialStateSaved = true;103}104}105void setRegister(uint64_t reg, RegisterSavedWhere newLocation,106int64_t newValue, PrologInfo &initialState) {107checkSaveRegister(reg, initialState);108savedRegisters[reg].location = newLocation;109savedRegisters[reg].value = newValue;110}111void setRegisterLocation(uint64_t reg, RegisterSavedWhere newLocation,112PrologInfo &initialState) {113checkSaveRegister(reg, initialState);114savedRegisters[reg].location = newLocation;115}116void setRegisterValue(uint64_t reg, int64_t newValue,117PrologInfo &initialState) {118checkSaveRegister(reg, initialState);119savedRegisters[reg].value = newValue;120}121void restoreRegisterToInitialState(uint64_t reg, PrologInfo &initialState) {122if (savedRegisters[reg].initialStateSaved)123savedRegisters[reg] = initialState.savedRegisters[reg];124// else the register still holds its initial state125}126};127128struct PrologInfoStackEntry {129PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i)130: next(n), info(i) {}131PrologInfoStackEntry *next;132PrologInfo info;133};134135struct RememberStack {136PrologInfoStackEntry *entry;137RememberStack() : entry(nullptr) {}138~RememberStack() {139#if defined(_LIBUNWIND_REMEMBER_CLEANUP_NEEDED)140// Clean up rememberStack. Even in the case where every141// DW_CFA_remember_state is paired with a DW_CFA_restore_state,142// parseInstructions can skip restore opcodes if it reaches the target PC143// and stops interpreting, so we have to make sure we don't leak memory.144while (entry) {145PrologInfoStackEntry *next = entry->next;146_LIBUNWIND_REMEMBER_FREE(entry);147entry = next;148}149#endif150}151};152153static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,154size_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,155CIE_Info *cieInfo);156static const char *decodeFDE(A &addressSpace, pint_t fdeStart,157FDE_Info *fdeInfo, CIE_Info *cieInfo,158bool useCIEInfo = false);159static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,160const CIE_Info &cieInfo, pint_t upToPC,161int arch, PrologInfo *results);162163static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);164};165166/// Parse a FDE into a CIE_Info and an FDE_Info. If useCIEInfo is167/// true, treat cieInfo as already-parsed CIE_Info (whose start offset168/// must match the one specified by the FDE) rather than parsing the169/// one indicated within the FDE.170template <typename A>171const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,172FDE_Info *fdeInfo, CIE_Info *cieInfo,173bool useCIEInfo) {174pint_t p = fdeStart;175pint_t cfiLength = (pint_t)addressSpace.get32(p);176p += 4;177if (cfiLength == 0xffffffff) {178// 0xffffffff means length is really next 8 bytes179cfiLength = (pint_t)addressSpace.get64(p);180p += 8;181}182if (cfiLength == 0)183return "FDE has zero length"; // zero terminator184uint32_t ciePointer = addressSpace.get32(p);185if (ciePointer == 0)186return "FDE is really a CIE"; // this is a CIE not an FDE187pint_t nextCFI = p + cfiLength;188pint_t cieStart = p - ciePointer;189if (useCIEInfo) {190if (cieInfo->cieStart != cieStart)191return "CIE start does not match";192} else {193const char *err = parseCIE(addressSpace, cieStart, cieInfo);194if (err != NULL)195return err;196}197p += 4;198// Parse pc begin and range.199pint_t pcStart =200addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);201pint_t pcRange =202addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);203// Parse rest of info.204fdeInfo->lsda = 0;205// Check for augmentation length.206if (cieInfo->fdesHaveAugmentationData) {207pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);208pint_t endOfAug = p + augLen;209if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {210// Peek at value (without indirection). Zero means no LSDA.211pint_t lsdaStart = p;212if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) !=2130) {214// Reset pointer and re-parse LSDA address.215p = lsdaStart;216fdeInfo->lsda =217addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);218}219}220p = endOfAug;221}222fdeInfo->fdeStart = fdeStart;223fdeInfo->fdeLength = nextCFI - fdeStart;224fdeInfo->fdeInstructions = p;225fdeInfo->pcStart = pcStart;226fdeInfo->pcEnd = pcStart + pcRange;227return NULL; // success228}229230/// Scan an eh_frame section to find an FDE for a pc231template <typename A>232bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,233size_t sectionLength, pint_t fdeHint,234FDE_Info *fdeInfo, CIE_Info *cieInfo) {235//fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);236pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;237const pint_t ehSectionEnd = (sectionLength == SIZE_MAX)238? static_cast<pint_t>(-1)239: (ehSectionStart + sectionLength);240while (p < ehSectionEnd) {241pint_t currentCFI = p;242//fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);243pint_t cfiLength = addressSpace.get32(p);244p += 4;245if (cfiLength == 0xffffffff) {246// 0xffffffff means length is really next 8 bytes247cfiLength = (pint_t)addressSpace.get64(p);248p += 8;249}250if (cfiLength == 0)251return false; // zero terminator252uint32_t id = addressSpace.get32(p);253if (id == 0) {254// Skip over CIEs.255p += cfiLength;256} else {257// Process FDE to see if it covers pc.258pint_t nextCFI = p + cfiLength;259uint32_t ciePointer = addressSpace.get32(p);260pint_t cieStart = p - ciePointer;261// Validate pointer to CIE is within section.262if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) {263if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) {264p += 4;265// Parse pc begin and range.266pint_t pcStart =267addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);268pint_t pcRange = addressSpace.getEncodedP(269p, nextCFI, cieInfo->pointerEncoding & 0x0F);270// Test if pc is within the function this FDE covers.271if ((pcStart < pc) && (pc <= pcStart + pcRange)) {272// parse rest of info273fdeInfo->lsda = 0;274// check for augmentation length275if (cieInfo->fdesHaveAugmentationData) {276pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);277pint_t endOfAug = p + augLen;278if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {279// Peek at value (without indirection). Zero means no LSDA.280pint_t lsdaStart = p;281if (addressSpace.getEncodedP(282p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) {283// Reset pointer and re-parse LSDA address.284p = lsdaStart;285fdeInfo->lsda = addressSpace286.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);287}288}289p = endOfAug;290}291fdeInfo->fdeStart = currentCFI;292fdeInfo->fdeLength = nextCFI - currentCFI;293fdeInfo->fdeInstructions = p;294fdeInfo->pcStart = pcStart;295fdeInfo->pcEnd = pcStart + pcRange;296return true;297} else {298// pc is not in begin/range, skip this FDE299}300} else {301// Malformed CIE, now augmentation describing pc range encoding.302}303} else {304// malformed FDE. CIE is bad305}306p = nextCFI;307}308}309return false;310}311312/// Extract info from a CIE313template <typename A>314const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,315CIE_Info *cieInfo) {316cieInfo->pointerEncoding = 0;317cieInfo->lsdaEncoding = DW_EH_PE_omit;318cieInfo->personalityEncoding = 0;319cieInfo->personalityOffsetInCIE = 0;320cieInfo->personality = 0;321cieInfo->codeAlignFactor = 0;322cieInfo->dataAlignFactor = 0;323cieInfo->isSignalFrame = false;324cieInfo->fdesHaveAugmentationData = false;325#if defined(_LIBUNWIND_TARGET_AARCH64)326cieInfo->addressesSignedWithBKey = false;327cieInfo->mteTaggedFrame = false;328#endif329cieInfo->cieStart = cie;330pint_t p = cie;331pint_t cieLength = (pint_t)addressSpace.get32(p);332p += 4;333pint_t cieContentEnd = p + cieLength;334if (cieLength == 0xffffffff) {335// 0xffffffff means length is really next 8 bytes336cieLength = (pint_t)addressSpace.get64(p);337p += 8;338cieContentEnd = p + cieLength;339}340if (cieLength == 0)341return NULL;342// CIE ID is always 0343if (addressSpace.get32(p) != 0)344return "CIE ID is not zero";345p += 4;346// Version is always 1 or 3347uint8_t version = addressSpace.get8(p);348if ((version != 1) && (version != 3))349return "CIE version is not 1 or 3";350++p;351// save start of augmentation string and find end352pint_t strStart = p;353while (addressSpace.get8(p) != 0)354++p;355++p;356// parse code alignment factor357cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd);358// parse data alignment factor359cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd);360// parse return address register361uint64_t raReg = (version == 1) ? addressSpace.get8(p++)362: addressSpace.getULEB128(p, cieContentEnd);363assert(raReg < 255 && "return address register too large");364cieInfo->returnAddressRegister = (uint8_t)raReg;365// parse augmentation data based on augmentation string366const char *result = NULL;367if (addressSpace.get8(strStart) == 'z') {368// parse augmentation data length369addressSpace.getULEB128(p, cieContentEnd);370for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) {371switch (addressSpace.get8(s)) {372case 'z':373cieInfo->fdesHaveAugmentationData = true;374break;375case 'P':376cieInfo->personalityEncoding = addressSpace.get8(p);377++p;378cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);379cieInfo->personality = addressSpace380.getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);381break;382case 'L':383cieInfo->lsdaEncoding = addressSpace.get8(p);384++p;385break;386case 'R':387cieInfo->pointerEncoding = addressSpace.get8(p);388++p;389break;390case 'S':391cieInfo->isSignalFrame = true;392break;393#if defined(_LIBUNWIND_TARGET_AARCH64)394case 'B':395cieInfo->addressesSignedWithBKey = true;396break;397case 'G':398cieInfo->mteTaggedFrame = true;399break;400#endif401default:402// ignore unknown letters403break;404}405}406}407cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;408cieInfo->cieInstructions = p;409return result;410}411412413/// "run" the DWARF instructions and create the abstract PrologInfo for an FDE414template <typename A>415bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,416const FDE_Info &fdeInfo,417const CIE_Info &cieInfo, pint_t upToPC,418int arch, PrologInfo *results) {419// Alloca is used for the allocation of the rememberStack entries. It removes420// the dependency on new/malloc but the below for loop can not be refactored421// into functions. Entry could be saved during the processing of a CIE and422// restored by an FDE.423RememberStack rememberStack;424425struct ParseInfo {426pint_t instructions;427pint_t instructionsEnd;428pint_t pcoffset;429};430431ParseInfo parseInfoArray[] = {432{cieInfo.cieInstructions, cieInfo.cieStart + cieInfo.cieLength,433(pint_t)(-1)},434{fdeInfo.fdeInstructions, fdeInfo.fdeStart + fdeInfo.fdeLength,435upToPC - fdeInfo.pcStart}};436437for (const auto &info : parseInfoArray) {438pint_t p = info.instructions;439pint_t instructionsEnd = info.instructionsEnd;440pint_t pcoffset = info.pcoffset;441pint_t codeOffset = 0;442443// initialState initialized as registers in results are modified. Use444// PrologInfo accessor functions to avoid reading uninitialized data.445PrologInfo initialState(PrologInfo::InitializeTime::kLazy);446447_LIBUNWIND_TRACE_DWARF("parseFDEInstructions(instructions=0x%0" PRIx64448")\n",449static_cast<uint64_t>(instructionsEnd));450451// see DWARF Spec, section 6.4.2 for details on unwind opcodes452while ((p < instructionsEnd) && (codeOffset < pcoffset)) {453uint64_t reg;454uint64_t reg2;455int64_t offset;456uint64_t length;457uint8_t opcode = addressSpace.get8(p);458uint8_t operand;459460++p;461switch (opcode) {462case DW_CFA_nop:463_LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n");464break;465case DW_CFA_set_loc:466codeOffset = addressSpace.getEncodedP(p, instructionsEnd,467cieInfo.pointerEncoding);468_LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n");469break;470case DW_CFA_advance_loc1:471codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);472p += 1;473_LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",474static_cast<uint64_t>(codeOffset));475break;476case DW_CFA_advance_loc2:477codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);478p += 2;479_LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",480static_cast<uint64_t>(codeOffset));481break;482case DW_CFA_advance_loc4:483codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);484p += 4;485_LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",486static_cast<uint64_t>(codeOffset));487break;488case DW_CFA_offset_extended:489reg = addressSpace.getULEB128(p, instructionsEnd);490offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *491cieInfo.dataAlignFactor;492if (reg > kMaxRegisterNumber) {493_LIBUNWIND_LOG0(494"malformed DW_CFA_offset_extended DWARF unwind, reg too big");495return false;496}497results->setRegister(reg, kRegisterInCFA, offset, initialState);498_LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", "499"offset=%" PRId64 ")\n",500reg, offset);501break;502case DW_CFA_restore_extended:503reg = addressSpace.getULEB128(p, instructionsEnd);504if (reg > kMaxRegisterNumber) {505_LIBUNWIND_LOG0(506"malformed DW_CFA_restore_extended DWARF unwind, reg too big");507return false;508}509results->restoreRegisterToInitialState(reg, initialState);510_LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n",511reg);512break;513case DW_CFA_undefined:514reg = addressSpace.getULEB128(p, instructionsEnd);515if (reg > kMaxRegisterNumber) {516_LIBUNWIND_LOG0(517"malformed DW_CFA_undefined DWARF unwind, reg too big");518return false;519}520results->setRegisterLocation(reg, kRegisterUnused, initialState);521_LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);522break;523case DW_CFA_same_value:524reg = addressSpace.getULEB128(p, instructionsEnd);525if (reg > kMaxRegisterNumber) {526_LIBUNWIND_LOG0(527"malformed DW_CFA_same_value DWARF unwind, reg too big");528return false;529}530// <rdar://problem/8456377> DW_CFA_same_value unsupported531// "same value" means register was stored in frame, but its current532// value has not changed, so no need to restore from frame.533// We model this as if the register was never saved.534results->setRegisterLocation(reg, kRegisterUnused, initialState);535_LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);536break;537case DW_CFA_register:538reg = addressSpace.getULEB128(p, instructionsEnd);539reg2 = addressSpace.getULEB128(p, instructionsEnd);540if (reg > kMaxRegisterNumber) {541_LIBUNWIND_LOG0(542"malformed DW_CFA_register DWARF unwind, reg too big");543return false;544}545if (reg2 > kMaxRegisterNumber) {546_LIBUNWIND_LOG0(547"malformed DW_CFA_register DWARF unwind, reg2 too big");548return false;549}550results->setRegister(reg, kRegisterInRegister, (int64_t)reg2,551initialState);552_LIBUNWIND_TRACE_DWARF(553"DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2);554break;555case DW_CFA_remember_state: {556// Avoid operator new because that would be an upward dependency.557// Avoid malloc because it needs heap allocation.558PrologInfoStackEntry *entry =559(PrologInfoStackEntry *)_LIBUNWIND_REMEMBER_ALLOC(560sizeof(PrologInfoStackEntry));561if (entry != NULL) {562entry->next = rememberStack.entry;563entry->info = *results;564rememberStack.entry = entry;565} else {566return false;567}568_LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n");569break;570}571case DW_CFA_restore_state:572if (rememberStack.entry != NULL) {573PrologInfoStackEntry *top = rememberStack.entry;574*results = top->info;575rememberStack.entry = top->next;576_LIBUNWIND_REMEMBER_FREE(top);577} else {578return false;579}580_LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n");581break;582case DW_CFA_def_cfa:583reg = addressSpace.getULEB128(p, instructionsEnd);584offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);585if (reg > kMaxRegisterNumber) {586_LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big");587return false;588}589results->cfaRegister = (uint32_t)reg;590results->cfaRegisterOffset = (int32_t)offset;591_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64592")\n",593reg, offset);594break;595case DW_CFA_def_cfa_register:596reg = addressSpace.getULEB128(p, instructionsEnd);597if (reg > kMaxRegisterNumber) {598_LIBUNWIND_LOG0(599"malformed DW_CFA_def_cfa_register DWARF unwind, reg too big");600return false;601}602results->cfaRegister = (uint32_t)reg;603_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);604break;605case DW_CFA_def_cfa_offset:606results->cfaRegisterOffset =607(int32_t)addressSpace.getULEB128(p, instructionsEnd);608_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n",609results->cfaRegisterOffset);610break;611case DW_CFA_def_cfa_expression:612results->cfaRegister = 0;613results->cfaExpression = (int64_t)p;614length = addressSpace.getULEB128(p, instructionsEnd);615assert(length < static_cast<pint_t>(~0) && "pointer overflow");616p += static_cast<pint_t>(length);617_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64618", length=%" PRIu64 ")\n",619results->cfaExpression, length);620break;621case DW_CFA_expression:622reg = addressSpace.getULEB128(p, instructionsEnd);623if (reg > kMaxRegisterNumber) {624_LIBUNWIND_LOG0(625"malformed DW_CFA_expression DWARF unwind, reg too big");626return false;627}628results->setRegister(reg, kRegisterAtExpression, (int64_t)p,629initialState);630length = addressSpace.getULEB128(p, instructionsEnd);631assert(length < static_cast<pint_t>(~0) && "pointer overflow");632p += static_cast<pint_t>(length);633_LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", "634"expression=0x%" PRIx64 ", "635"length=%" PRIu64 ")\n",636reg, results->savedRegisters[reg].value, length);637break;638case DW_CFA_offset_extended_sf:639reg = addressSpace.getULEB128(p, instructionsEnd);640if (reg > kMaxRegisterNumber) {641_LIBUNWIND_LOG0(642"malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big");643return false;644}645offset = addressSpace.getSLEB128(p, instructionsEnd) *646cieInfo.dataAlignFactor;647results->setRegister(reg, kRegisterInCFA, offset, initialState);648_LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", "649"offset=%" PRId64 ")\n",650reg, offset);651break;652case DW_CFA_def_cfa_sf:653reg = addressSpace.getULEB128(p, instructionsEnd);654offset = addressSpace.getSLEB128(p, instructionsEnd) *655cieInfo.dataAlignFactor;656if (reg > kMaxRegisterNumber) {657_LIBUNWIND_LOG0(658"malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big");659return false;660}661results->cfaRegister = (uint32_t)reg;662results->cfaRegisterOffset = (int32_t)offset;663_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", "664"offset=%" PRId64 ")\n",665reg, offset);666break;667case DW_CFA_def_cfa_offset_sf:668results->cfaRegisterOffset =669(int32_t)(addressSpace.getSLEB128(p, instructionsEnd) *670cieInfo.dataAlignFactor);671_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n",672results->cfaRegisterOffset);673break;674case DW_CFA_val_offset:675reg = addressSpace.getULEB128(p, instructionsEnd);676if (reg > kMaxRegisterNumber) {677_LIBUNWIND_LOG(678"malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64679") out of range\n",680reg);681return false;682}683offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *684cieInfo.dataAlignFactor;685results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);686_LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "687"offset=%" PRId64 "\n",688reg, offset);689break;690case DW_CFA_val_offset_sf:691reg = addressSpace.getULEB128(p, instructionsEnd);692if (reg > kMaxRegisterNumber) {693_LIBUNWIND_LOG0(694"malformed DW_CFA_val_offset_sf DWARF unwind, reg too big");695return false;696}697offset = addressSpace.getSLEB128(p, instructionsEnd) *698cieInfo.dataAlignFactor;699results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);700_LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "701"offset=%" PRId64 "\n",702reg, offset);703break;704case DW_CFA_val_expression:705reg = addressSpace.getULEB128(p, instructionsEnd);706if (reg > kMaxRegisterNumber) {707_LIBUNWIND_LOG0(708"malformed DW_CFA_val_expression DWARF unwind, reg too big");709return false;710}711results->setRegister(reg, kRegisterIsExpression, (int64_t)p,712initialState);713length = addressSpace.getULEB128(p, instructionsEnd);714assert(length < static_cast<pint_t>(~0) && "pointer overflow");715p += static_cast<pint_t>(length);716_LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "717"expression=0x%" PRIx64 ", length=%" PRIu64718")\n",719reg, results->savedRegisters[reg].value, length);720break;721case DW_CFA_GNU_args_size:722length = addressSpace.getULEB128(p, instructionsEnd);723results->spExtraArgSize = (uint32_t)length;724_LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);725break;726case DW_CFA_GNU_negative_offset_extended:727reg = addressSpace.getULEB128(p, instructionsEnd);728if (reg > kMaxRegisterNumber) {729_LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF "730"unwind, reg too big");731return false;732}733offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *734cieInfo.dataAlignFactor;735results->setRegister(reg, kRegisterInCFA, -offset, initialState);736_LIBUNWIND_TRACE_DWARF(737"DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);738break;739740#if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC) || \741defined(_LIBUNWIND_TARGET_SPARC64)742// The same constant is used to represent different instructions on743// AArch64 (negate_ra_state) and SPARC (window_save).744static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save,745"uses the same constant");746case DW_CFA_AARCH64_negate_ra_state:747switch (arch) {748#if defined(_LIBUNWIND_TARGET_AARCH64)749case REGISTERS_ARM64: {750int64_t value =751results->savedRegisters[UNW_AARCH64_RA_SIGN_STATE].value ^ 0x1;752results->setRegisterValue(UNW_AARCH64_RA_SIGN_STATE, value,753initialState);754_LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n");755} break;756#endif757758#if defined(_LIBUNWIND_TARGET_SPARC)759// case DW_CFA_GNU_window_save:760case REGISTERS_SPARC:761_LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n");762for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) {763results->setRegister(reg, kRegisterInRegister,764((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0,765initialState);766}767768for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {769results->setRegister(reg, kRegisterInCFA,770((int64_t)reg - UNW_SPARC_L0) * 4,771initialState);772}773break;774#endif775776#if defined(_LIBUNWIND_TARGET_SPARC64)777// case DW_CFA_GNU_window_save:778case REGISTERS_SPARC64:779// Don't save %o0-%o7 on sparc64.780// https://reviews.llvm.org/D32450#736405781782for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {783if (reg == UNW_SPARC_I7)784results->setRegister(785reg, kRegisterInCFADecrypt,786static_cast<int64_t>((reg - UNW_SPARC_L0) * sizeof(pint_t)),787initialState);788else789results->setRegister(790reg, kRegisterInCFA,791static_cast<int64_t>((reg - UNW_SPARC_L0) * sizeof(pint_t)),792initialState);793}794_LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save\n");795break;796#endif797}798break;799800#else801(void)arch;802#endif803804default:805operand = opcode & 0x3F;806switch (opcode & 0xC0) {807case DW_CFA_offset:808reg = operand;809if (reg > kMaxRegisterNumber) {810_LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64811") out of range",812reg);813return false;814}815offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *816cieInfo.dataAlignFactor;817results->setRegister(reg, kRegisterInCFA, offset, initialState);818_LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",819operand, offset);820break;821case DW_CFA_advance_loc:822codeOffset += operand * cieInfo.codeAlignFactor;823_LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",824static_cast<uint64_t>(codeOffset));825break;826case DW_CFA_restore:827reg = operand;828if (reg > kMaxRegisterNumber) {829_LIBUNWIND_LOG(830"malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64831") out of range",832reg);833return false;834}835results->restoreRegisterToInitialState(reg, initialState);836_LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",837static_cast<uint64_t>(operand));838break;839default:840_LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);841return false;842}843}844}845}846return true;847}848849} // namespace libunwind850851#endif // __DWARF_PARSER_HPP__852853854