Path: blob/main/contrib/llvm-project/libunwind/src/CompactUnwinder.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// Does runtime stack unwinding using compact unwind encodings.8//9//===----------------------------------------------------------------------===//1011#ifndef __COMPACT_UNWINDER_HPP__12#define __COMPACT_UNWINDER_HPP__1314#include <stdint.h>15#include <stdlib.h>1617#include <libunwind.h>18#include <mach-o/compact_unwind_encoding.h>1920#include "Registers.hpp"21#include "libunwind_ext.h"2223#define EXTRACT_BITS(value, mask) \24((value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask))) - 1))2526namespace libunwind {2728#if defined(_LIBUNWIND_TARGET_I386)29/// CompactUnwinder_x86 uses a compact unwind info to virtually "step" (aka30/// unwind) by modifying a Registers_x86 register set31template <typename A>32class CompactUnwinder_x86 {33public:3435static int stepWithCompactEncoding(compact_unwind_encoding_t info,36uint32_t functionStart, A &addressSpace,37Registers_x86 ®isters);3839private:40typename A::pint_t pint_t;4142static void frameUnwind(A &addressSpace, Registers_x86 ®isters);43static void framelessUnwind(A &addressSpace,44typename A::pint_t returnAddressLocation,45Registers_x86 ®isters);46static int47stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding,48uint32_t functionStart, A &addressSpace,49Registers_x86 ®isters);50static int stepWithCompactEncodingFrameless(51compact_unwind_encoding_t compactEncoding, uint32_t functionStart,52A &addressSpace, Registers_x86 ®isters, bool indirectStackSize);53};5455template <typename A>56int CompactUnwinder_x86<A>::stepWithCompactEncoding(57compact_unwind_encoding_t compactEncoding, uint32_t functionStart,58A &addressSpace, Registers_x86 ®isters) {59switch (compactEncoding & UNWIND_X86_MODE_MASK) {60case UNWIND_X86_MODE_EBP_FRAME:61return stepWithCompactEncodingEBPFrame(compactEncoding, functionStart,62addressSpace, registers);63case UNWIND_X86_MODE_STACK_IMMD:64return stepWithCompactEncodingFrameless(compactEncoding, functionStart,65addressSpace, registers, false);66case UNWIND_X86_MODE_STACK_IND:67return stepWithCompactEncodingFrameless(compactEncoding, functionStart,68addressSpace, registers, true);69}70_LIBUNWIND_ABORT("invalid compact unwind encoding");71}7273template <typename A>74int CompactUnwinder_x86<A>::stepWithCompactEncodingEBPFrame(75compact_unwind_encoding_t compactEncoding, uint32_t functionStart,76A &addressSpace, Registers_x86 ®isters) {77uint32_t savedRegistersOffset =78EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_OFFSET);79uint32_t savedRegistersLocations =80EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_REGISTERS);8182uint32_t savedRegisters = registers.getEBP() - 4 * savedRegistersOffset;83for (int i = 0; i < 5; ++i) {84switch (savedRegistersLocations & 0x7) {85case UNWIND_X86_REG_NONE:86// no register saved in this slot87break;88case UNWIND_X86_REG_EBX:89registers.setEBX(addressSpace.get32(savedRegisters));90break;91case UNWIND_X86_REG_ECX:92registers.setECX(addressSpace.get32(savedRegisters));93break;94case UNWIND_X86_REG_EDX:95registers.setEDX(addressSpace.get32(savedRegisters));96break;97case UNWIND_X86_REG_EDI:98registers.setEDI(addressSpace.get32(savedRegisters));99break;100case UNWIND_X86_REG_ESI:101registers.setESI(addressSpace.get32(savedRegisters));102break;103default:104(void)functionStart;105_LIBUNWIND_DEBUG_LOG("bad register for EBP frame, encoding=%08X for "106"function starting at 0x%X",107compactEncoding, functionStart);108_LIBUNWIND_ABORT("invalid compact unwind encoding");109}110savedRegisters += 4;111savedRegistersLocations = (savedRegistersLocations >> 3);112}113frameUnwind(addressSpace, registers);114return UNW_STEP_SUCCESS;115}116117template <typename A>118int CompactUnwinder_x86<A>::stepWithCompactEncodingFrameless(119compact_unwind_encoding_t encoding, uint32_t functionStart,120A &addressSpace, Registers_x86 ®isters, bool indirectStackSize) {121uint32_t stackSizeEncoded =122EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);123uint32_t stackAdjust =124EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST);125uint32_t regCount =126EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);127uint32_t permutation =128EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);129uint32_t stackSize = stackSizeEncoded * 4;130if (indirectStackSize) {131// stack size is encoded in subl $xxx,%esp instruction132uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded);133stackSize = subl + 4 * stackAdjust;134}135// decompress permutation136uint32_t permunreg[6];137switch (regCount) {138case 6:139permunreg[0] = permutation / 120;140permutation -= (permunreg[0] * 120);141permunreg[1] = permutation / 24;142permutation -= (permunreg[1] * 24);143permunreg[2] = permutation / 6;144permutation -= (permunreg[2] * 6);145permunreg[3] = permutation / 2;146permutation -= (permunreg[3] * 2);147permunreg[4] = permutation;148permunreg[5] = 0;149break;150case 5:151permunreg[0] = permutation / 120;152permutation -= (permunreg[0] * 120);153permunreg[1] = permutation / 24;154permutation -= (permunreg[1] * 24);155permunreg[2] = permutation / 6;156permutation -= (permunreg[2] * 6);157permunreg[3] = permutation / 2;158permutation -= (permunreg[3] * 2);159permunreg[4] = permutation;160break;161case 4:162permunreg[0] = permutation / 60;163permutation -= (permunreg[0] * 60);164permunreg[1] = permutation / 12;165permutation -= (permunreg[1] * 12);166permunreg[2] = permutation / 3;167permutation -= (permunreg[2] * 3);168permunreg[3] = permutation;169break;170case 3:171permunreg[0] = permutation / 20;172permutation -= (permunreg[0] * 20);173permunreg[1] = permutation / 4;174permutation -= (permunreg[1] * 4);175permunreg[2] = permutation;176break;177case 2:178permunreg[0] = permutation / 5;179permutation -= (permunreg[0] * 5);180permunreg[1] = permutation;181break;182case 1:183permunreg[0] = permutation;184break;185}186// re-number registers back to standard numbers187int registersSaved[6];188bool used[7] = { false, false, false, false, false, false, false };189for (uint32_t i = 0; i < regCount; ++i) {190uint32_t renum = 0;191for (int u = 1; u < 7; ++u) {192if (!used[u]) {193if (renum == permunreg[i]) {194registersSaved[i] = u;195used[u] = true;196break;197}198++renum;199}200}201}202uint32_t savedRegisters = registers.getSP() + stackSize - 4 - 4 * regCount;203for (uint32_t i = 0; i < regCount; ++i) {204switch (registersSaved[i]) {205case UNWIND_X86_REG_EBX:206registers.setEBX(addressSpace.get32(savedRegisters));207break;208case UNWIND_X86_REG_ECX:209registers.setECX(addressSpace.get32(savedRegisters));210break;211case UNWIND_X86_REG_EDX:212registers.setEDX(addressSpace.get32(savedRegisters));213break;214case UNWIND_X86_REG_EDI:215registers.setEDI(addressSpace.get32(savedRegisters));216break;217case UNWIND_X86_REG_ESI:218registers.setESI(addressSpace.get32(savedRegisters));219break;220case UNWIND_X86_REG_EBP:221registers.setEBP(addressSpace.get32(savedRegisters));222break;223default:224_LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for "225"function starting at 0x%X",226encoding, functionStart);227_LIBUNWIND_ABORT("invalid compact unwind encoding");228}229savedRegisters += 4;230}231framelessUnwind(addressSpace, savedRegisters, registers);232return UNW_STEP_SUCCESS;233}234235236template <typename A>237void CompactUnwinder_x86<A>::frameUnwind(A &addressSpace,238Registers_x86 ®isters) {239typename A::pint_t bp = registers.getEBP();240// ebp points to old ebp241registers.setEBP(addressSpace.get32(bp));242// old esp is ebp less saved ebp and return address243registers.setSP((uint32_t)bp + 8);244// pop return address into eip245registers.setIP(addressSpace.get32(bp + 4));246}247248template <typename A>249void CompactUnwinder_x86<A>::framelessUnwind(250A &addressSpace, typename A::pint_t returnAddressLocation,251Registers_x86 ®isters) {252// return address is on stack after last saved register253registers.setIP(addressSpace.get32(returnAddressLocation));254// old esp is before return address255registers.setSP((uint32_t)returnAddressLocation + 4);256}257#endif // _LIBUNWIND_TARGET_I386258259260#if defined(_LIBUNWIND_TARGET_X86_64)261/// CompactUnwinder_x86_64 uses a compact unwind info to virtually "step" (aka262/// unwind) by modifying a Registers_x86_64 register set263template <typename A>264class CompactUnwinder_x86_64 {265public:266267static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,268uint64_t functionStart, A &addressSpace,269Registers_x86_64 ®isters);270271private:272typename A::pint_t pint_t;273274static void frameUnwind(A &addressSpace, Registers_x86_64 ®isters);275static void framelessUnwind(A &addressSpace, uint64_t returnAddressLocation,276Registers_x86_64 ®isters);277static int278stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding,279uint64_t functionStart, A &addressSpace,280Registers_x86_64 ®isters);281static int stepWithCompactEncodingFrameless(282compact_unwind_encoding_t compactEncoding, uint64_t functionStart,283A &addressSpace, Registers_x86_64 ®isters, bool indirectStackSize);284};285286template <typename A>287int CompactUnwinder_x86_64<A>::stepWithCompactEncoding(288compact_unwind_encoding_t compactEncoding, uint64_t functionStart,289A &addressSpace, Registers_x86_64 ®isters) {290switch (compactEncoding & UNWIND_X86_64_MODE_MASK) {291case UNWIND_X86_64_MODE_RBP_FRAME:292return stepWithCompactEncodingRBPFrame(compactEncoding, functionStart,293addressSpace, registers);294case UNWIND_X86_64_MODE_STACK_IMMD:295return stepWithCompactEncodingFrameless(compactEncoding, functionStart,296addressSpace, registers, false);297case UNWIND_X86_64_MODE_STACK_IND:298return stepWithCompactEncodingFrameless(compactEncoding, functionStart,299addressSpace, registers, true);300}301_LIBUNWIND_ABORT("invalid compact unwind encoding");302}303304template <typename A>305int CompactUnwinder_x86_64<A>::stepWithCompactEncodingRBPFrame(306compact_unwind_encoding_t compactEncoding, uint64_t functionStart,307A &addressSpace, Registers_x86_64 ®isters) {308uint32_t savedRegistersOffset =309EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_OFFSET);310uint32_t savedRegistersLocations =311EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);312313uint64_t savedRegisters = registers.getRBP() - 8 * savedRegistersOffset;314for (int i = 0; i < 5; ++i) {315switch (savedRegistersLocations & 0x7) {316case UNWIND_X86_64_REG_NONE:317// no register saved in this slot318break;319case UNWIND_X86_64_REG_RBX:320registers.setRBX(addressSpace.get64(savedRegisters));321break;322case UNWIND_X86_64_REG_R12:323registers.setR12(addressSpace.get64(savedRegisters));324break;325case UNWIND_X86_64_REG_R13:326registers.setR13(addressSpace.get64(savedRegisters));327break;328case UNWIND_X86_64_REG_R14:329registers.setR14(addressSpace.get64(savedRegisters));330break;331case UNWIND_X86_64_REG_R15:332registers.setR15(addressSpace.get64(savedRegisters));333break;334default:335(void)functionStart;336_LIBUNWIND_DEBUG_LOG("bad register for RBP frame, encoding=%08X for "337"function starting at 0x%llX",338compactEncoding, functionStart);339_LIBUNWIND_ABORT("invalid compact unwind encoding");340}341savedRegisters += 8;342savedRegistersLocations = (savedRegistersLocations >> 3);343}344frameUnwind(addressSpace, registers);345return UNW_STEP_SUCCESS;346}347348template <typename A>349int CompactUnwinder_x86_64<A>::stepWithCompactEncodingFrameless(350compact_unwind_encoding_t encoding, uint64_t functionStart, A &addressSpace,351Registers_x86_64 ®isters, bool indirectStackSize) {352uint32_t stackSizeEncoded =353EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);354uint32_t stackAdjust =355EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);356uint32_t regCount =357EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);358uint32_t permutation =359EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);360uint32_t stackSize = stackSizeEncoded * 8;361if (indirectStackSize) {362// stack size is encoded in subl $xxx,%esp instruction363uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded);364stackSize = subl + 8 * stackAdjust;365}366// decompress permutation367uint32_t permunreg[6];368switch (regCount) {369case 6:370permunreg[0] = permutation / 120;371permutation -= (permunreg[0] * 120);372permunreg[1] = permutation / 24;373permutation -= (permunreg[1] * 24);374permunreg[2] = permutation / 6;375permutation -= (permunreg[2] * 6);376permunreg[3] = permutation / 2;377permutation -= (permunreg[3] * 2);378permunreg[4] = permutation;379permunreg[5] = 0;380break;381case 5:382permunreg[0] = permutation / 120;383permutation -= (permunreg[0] * 120);384permunreg[1] = permutation / 24;385permutation -= (permunreg[1] * 24);386permunreg[2] = permutation / 6;387permutation -= (permunreg[2] * 6);388permunreg[3] = permutation / 2;389permutation -= (permunreg[3] * 2);390permunreg[4] = permutation;391break;392case 4:393permunreg[0] = permutation / 60;394permutation -= (permunreg[0] * 60);395permunreg[1] = permutation / 12;396permutation -= (permunreg[1] * 12);397permunreg[2] = permutation / 3;398permutation -= (permunreg[2] * 3);399permunreg[3] = permutation;400break;401case 3:402permunreg[0] = permutation / 20;403permutation -= (permunreg[0] * 20);404permunreg[1] = permutation / 4;405permutation -= (permunreg[1] * 4);406permunreg[2] = permutation;407break;408case 2:409permunreg[0] = permutation / 5;410permutation -= (permunreg[0] * 5);411permunreg[1] = permutation;412break;413case 1:414permunreg[0] = permutation;415break;416}417// re-number registers back to standard numbers418int registersSaved[6];419bool used[7] = { false, false, false, false, false, false, false };420for (uint32_t i = 0; i < regCount; ++i) {421uint32_t renum = 0;422for (int u = 1; u < 7; ++u) {423if (!used[u]) {424if (renum == permunreg[i]) {425registersSaved[i] = u;426used[u] = true;427break;428}429++renum;430}431}432}433uint64_t savedRegisters = registers.getSP() + stackSize - 8 - 8 * regCount;434for (uint32_t i = 0; i < regCount; ++i) {435switch (registersSaved[i]) {436case UNWIND_X86_64_REG_RBX:437registers.setRBX(addressSpace.get64(savedRegisters));438break;439case UNWIND_X86_64_REG_R12:440registers.setR12(addressSpace.get64(savedRegisters));441break;442case UNWIND_X86_64_REG_R13:443registers.setR13(addressSpace.get64(savedRegisters));444break;445case UNWIND_X86_64_REG_R14:446registers.setR14(addressSpace.get64(savedRegisters));447break;448case UNWIND_X86_64_REG_R15:449registers.setR15(addressSpace.get64(savedRegisters));450break;451case UNWIND_X86_64_REG_RBP:452registers.setRBP(addressSpace.get64(savedRegisters));453break;454default:455_LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for "456"function starting at 0x%llX",457encoding, functionStart);458_LIBUNWIND_ABORT("invalid compact unwind encoding");459}460savedRegisters += 8;461}462framelessUnwind(addressSpace, savedRegisters, registers);463return UNW_STEP_SUCCESS;464}465466467template <typename A>468void CompactUnwinder_x86_64<A>::frameUnwind(A &addressSpace,469Registers_x86_64 ®isters) {470uint64_t rbp = registers.getRBP();471// ebp points to old ebp472registers.setRBP(addressSpace.get64(rbp));473// old esp is ebp less saved ebp and return address474registers.setSP(rbp + 16);475// pop return address into eip476registers.setIP(addressSpace.get64(rbp + 8));477}478479template <typename A>480void CompactUnwinder_x86_64<A>::framelessUnwind(A &addressSpace,481uint64_t returnAddressLocation,482Registers_x86_64 ®isters) {483// return address is on stack after last saved register484registers.setIP(addressSpace.get64(returnAddressLocation));485// old esp is before return address486registers.setSP(returnAddressLocation + 8);487}488#endif // _LIBUNWIND_TARGET_X86_64489490491492#if defined(_LIBUNWIND_TARGET_AARCH64)493/// CompactUnwinder_arm64 uses a compact unwind info to virtually "step" (aka494/// unwind) by modifying a Registers_arm64 register set495template <typename A>496class CompactUnwinder_arm64 {497public:498499static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,500uint64_t functionStart, A &addressSpace,501Registers_arm64 ®isters);502503private:504typename A::pint_t pint_t;505506static int507stepWithCompactEncodingFrame(compact_unwind_encoding_t compactEncoding,508uint64_t functionStart, A &addressSpace,509Registers_arm64 ®isters);510static int stepWithCompactEncodingFrameless(511compact_unwind_encoding_t compactEncoding, uint64_t functionStart,512A &addressSpace, Registers_arm64 ®isters);513};514515template <typename A>516int CompactUnwinder_arm64<A>::stepWithCompactEncoding(517compact_unwind_encoding_t compactEncoding, uint64_t functionStart,518A &addressSpace, Registers_arm64 ®isters) {519switch (compactEncoding & UNWIND_ARM64_MODE_MASK) {520case UNWIND_ARM64_MODE_FRAME:521return stepWithCompactEncodingFrame(compactEncoding, functionStart,522addressSpace, registers);523case UNWIND_ARM64_MODE_FRAMELESS:524return stepWithCompactEncodingFrameless(compactEncoding, functionStart,525addressSpace, registers);526}527_LIBUNWIND_ABORT("invalid compact unwind encoding");528}529530template <typename A>531int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrameless(532compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,533Registers_arm64 ®isters) {534uint32_t stackSize =53516 * EXTRACT_BITS(encoding, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK);536537uint64_t savedRegisterLoc = registers.getSP() + stackSize;538539if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) {540registers.setRegister(UNW_AARCH64_X19, addressSpace.get64(savedRegisterLoc));541savedRegisterLoc -= 8;542registers.setRegister(UNW_AARCH64_X20, addressSpace.get64(savedRegisterLoc));543savedRegisterLoc -= 8;544}545if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) {546registers.setRegister(UNW_AARCH64_X21, addressSpace.get64(savedRegisterLoc));547savedRegisterLoc -= 8;548registers.setRegister(UNW_AARCH64_X22, addressSpace.get64(savedRegisterLoc));549savedRegisterLoc -= 8;550}551if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) {552registers.setRegister(UNW_AARCH64_X23, addressSpace.get64(savedRegisterLoc));553savedRegisterLoc -= 8;554registers.setRegister(UNW_AARCH64_X24, addressSpace.get64(savedRegisterLoc));555savedRegisterLoc -= 8;556}557if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) {558registers.setRegister(UNW_AARCH64_X25, addressSpace.get64(savedRegisterLoc));559savedRegisterLoc -= 8;560registers.setRegister(UNW_AARCH64_X26, addressSpace.get64(savedRegisterLoc));561savedRegisterLoc -= 8;562}563if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) {564registers.setRegister(UNW_AARCH64_X27, addressSpace.get64(savedRegisterLoc));565savedRegisterLoc -= 8;566registers.setRegister(UNW_AARCH64_X28, addressSpace.get64(savedRegisterLoc));567savedRegisterLoc -= 8;568}569570if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) {571registers.setFloatRegister(UNW_AARCH64_V8,572addressSpace.getDouble(savedRegisterLoc));573savedRegisterLoc -= 8;574registers.setFloatRegister(UNW_AARCH64_V9,575addressSpace.getDouble(savedRegisterLoc));576savedRegisterLoc -= 8;577}578if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) {579registers.setFloatRegister(UNW_AARCH64_V10,580addressSpace.getDouble(savedRegisterLoc));581savedRegisterLoc -= 8;582registers.setFloatRegister(UNW_AARCH64_V11,583addressSpace.getDouble(savedRegisterLoc));584savedRegisterLoc -= 8;585}586if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) {587registers.setFloatRegister(UNW_AARCH64_V12,588addressSpace.getDouble(savedRegisterLoc));589savedRegisterLoc -= 8;590registers.setFloatRegister(UNW_AARCH64_V13,591addressSpace.getDouble(savedRegisterLoc));592savedRegisterLoc -= 8;593}594if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) {595registers.setFloatRegister(UNW_AARCH64_V14,596addressSpace.getDouble(savedRegisterLoc));597savedRegisterLoc -= 8;598registers.setFloatRegister(UNW_AARCH64_V15,599addressSpace.getDouble(savedRegisterLoc));600savedRegisterLoc -= 8;601}602603// subtract stack size off of sp604registers.setSP(savedRegisterLoc);605606// set pc to be value in lr607registers.setIP(registers.getRegister(UNW_AARCH64_LR));608609return UNW_STEP_SUCCESS;610}611612template <typename A>613int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrame(614compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,615Registers_arm64 ®isters) {616uint64_t savedRegisterLoc = registers.getFP() - 8;617618if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) {619registers.setRegister(UNW_AARCH64_X19, addressSpace.get64(savedRegisterLoc));620savedRegisterLoc -= 8;621registers.setRegister(UNW_AARCH64_X20, addressSpace.get64(savedRegisterLoc));622savedRegisterLoc -= 8;623}624if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) {625registers.setRegister(UNW_AARCH64_X21, addressSpace.get64(savedRegisterLoc));626savedRegisterLoc -= 8;627registers.setRegister(UNW_AARCH64_X22, addressSpace.get64(savedRegisterLoc));628savedRegisterLoc -= 8;629}630if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) {631registers.setRegister(UNW_AARCH64_X23, addressSpace.get64(savedRegisterLoc));632savedRegisterLoc -= 8;633registers.setRegister(UNW_AARCH64_X24, addressSpace.get64(savedRegisterLoc));634savedRegisterLoc -= 8;635}636if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) {637registers.setRegister(UNW_AARCH64_X25, addressSpace.get64(savedRegisterLoc));638savedRegisterLoc -= 8;639registers.setRegister(UNW_AARCH64_X26, addressSpace.get64(savedRegisterLoc));640savedRegisterLoc -= 8;641}642if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) {643registers.setRegister(UNW_AARCH64_X27, addressSpace.get64(savedRegisterLoc));644savedRegisterLoc -= 8;645registers.setRegister(UNW_AARCH64_X28, addressSpace.get64(savedRegisterLoc));646savedRegisterLoc -= 8;647}648649if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) {650registers.setFloatRegister(UNW_AARCH64_V8,651addressSpace.getDouble(savedRegisterLoc));652savedRegisterLoc -= 8;653registers.setFloatRegister(UNW_AARCH64_V9,654addressSpace.getDouble(savedRegisterLoc));655savedRegisterLoc -= 8;656}657if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) {658registers.setFloatRegister(UNW_AARCH64_V10,659addressSpace.getDouble(savedRegisterLoc));660savedRegisterLoc -= 8;661registers.setFloatRegister(UNW_AARCH64_V11,662addressSpace.getDouble(savedRegisterLoc));663savedRegisterLoc -= 8;664}665if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) {666registers.setFloatRegister(UNW_AARCH64_V12,667addressSpace.getDouble(savedRegisterLoc));668savedRegisterLoc -= 8;669registers.setFloatRegister(UNW_AARCH64_V13,670addressSpace.getDouble(savedRegisterLoc));671savedRegisterLoc -= 8;672}673if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) {674registers.setFloatRegister(UNW_AARCH64_V14,675addressSpace.getDouble(savedRegisterLoc));676savedRegisterLoc -= 8;677registers.setFloatRegister(UNW_AARCH64_V15,678addressSpace.getDouble(savedRegisterLoc));679savedRegisterLoc -= 8;680}681682uint64_t fp = registers.getFP();683// fp points to old fp684registers.setFP(addressSpace.get64(fp));685// old sp is fp less saved fp and lr686registers.setSP(fp + 16);687// pop return address into pc688registers.setIP(addressSpace.get64(fp + 8));689690return UNW_STEP_SUCCESS;691}692#endif // _LIBUNWIND_TARGET_AARCH64693694695} // namespace libunwind696697#endif // __COMPACT_UNWINDER_HPP__698699700