| Index: third_party/libc++abi/src/Unwind/CompactUnwinder.hpp
|
| ===================================================================
|
| --- third_party/libc++abi/src/Unwind/CompactUnwinder.hpp (revision 0)
|
| +++ third_party/libc++abi/src/Unwind/CompactUnwinder.hpp (revision 0)
|
| @@ -0,0 +1,693 @@
|
| +//===-------------------------- CompactUnwinder.hpp -----------------------===//
|
| +//
|
| +// The LLVM Compiler Infrastructure
|
| +//
|
| +// This file is dual licensed under the MIT and the University of Illinois Open
|
| +// Source Licenses. See LICENSE.TXT for details.
|
| +//
|
| +//
|
| +// Does runtime stack unwinding using compact unwind encodings.
|
| +//
|
| +//===----------------------------------------------------------------------===//
|
| +
|
| +#ifndef __COMPACT_UNWINDER_HPP__
|
| +#define __COMPACT_UNWINDER_HPP__
|
| +
|
| +#include <stdint.h>
|
| +#include <stdlib.h>
|
| +
|
| +#include <libunwind.h>
|
| +#include <mach-o/compact_unwind_encoding.h>
|
| +
|
| +#include "AddressSpace.hpp"
|
| +#include "Registers.hpp"
|
| +
|
| +#define EXTRACT_BITS(value, mask) \
|
| + ((value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask))) - 1))
|
| +
|
| +namespace libunwind {
|
| +
|
| +/// CompactUnwinder_x86 uses a compact unwind info to virtually "step" (aka
|
| +/// unwind) by modifying a Registers_x86 register set
|
| +template <typename A>
|
| +class CompactUnwinder_x86 {
|
| +public:
|
| +
|
| + static int stepWithCompactEncoding(compact_unwind_encoding_t info,
|
| + uint32_t functionStart, A &addressSpace,
|
| + Registers_x86 ®isters);
|
| +
|
| +private:
|
| + typename A::pint_t pint_t;
|
| +
|
| + static void frameUnwind(A &addressSpace, Registers_x86 ®isters);
|
| + static void framelessUnwind(A &addressSpace,
|
| + typename A::pint_t returnAddressLocation,
|
| + Registers_x86 ®isters);
|
| + static int
|
| + stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding,
|
| + uint32_t functionStart, A &addressSpace,
|
| + Registers_x86 ®isters);
|
| + static int stepWithCompactEncodingFrameless(
|
| + compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
|
| + A &addressSpace, Registers_x86 ®isters, bool indirectStackSize);
|
| +};
|
| +
|
| +template <typename A>
|
| +int CompactUnwinder_x86<A>::stepWithCompactEncoding(
|
| + compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
|
| + A &addressSpace, Registers_x86 ®isters) {
|
| + switch (compactEncoding & UNWIND_X86_MODE_MASK) {
|
| + case UNWIND_X86_MODE_EBP_FRAME:
|
| + return stepWithCompactEncodingEBPFrame(compactEncoding, functionStart,
|
| + addressSpace, registers);
|
| + case UNWIND_X86_MODE_STACK_IMMD:
|
| + return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
|
| + addressSpace, registers, false);
|
| + case UNWIND_X86_MODE_STACK_IND:
|
| + return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
|
| + addressSpace, registers, true);
|
| + }
|
| + _LIBUNWIND_ABORT("invalid compact unwind encoding");
|
| +}
|
| +
|
| +template <typename A>
|
| +int CompactUnwinder_x86<A>::stepWithCompactEncodingEBPFrame(
|
| + compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
|
| + A &addressSpace, Registers_x86 ®isters) {
|
| + uint32_t savedRegistersOffset =
|
| + EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_OFFSET);
|
| + uint32_t savedRegistersLocations =
|
| + EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_REGISTERS);
|
| +
|
| + uint32_t savedRegisters = registers.getEBP() - 4 * savedRegistersOffset;
|
| + for (int i = 0; i < 5; ++i) {
|
| + switch (savedRegistersLocations & 0x7) {
|
| + case UNWIND_X86_REG_NONE:
|
| + // no register saved in this slot
|
| + break;
|
| + case UNWIND_X86_REG_EBX:
|
| + registers.setEBX(addressSpace.get32(savedRegisters));
|
| + break;
|
| + case UNWIND_X86_REG_ECX:
|
| + registers.setECX(addressSpace.get32(savedRegisters));
|
| + break;
|
| + case UNWIND_X86_REG_EDX:
|
| + registers.setEDX(addressSpace.get32(savedRegisters));
|
| + break;
|
| + case UNWIND_X86_REG_EDI:
|
| + registers.setEDI(addressSpace.get32(savedRegisters));
|
| + break;
|
| + case UNWIND_X86_REG_ESI:
|
| + registers.setESI(addressSpace.get32(savedRegisters));
|
| + break;
|
| + default:
|
| + (void)functionStart;
|
| + _LIBUNWIND_DEBUG_LOG("bad register for EBP frame, encoding=%08X for "
|
| + "function starting at 0x%X\n",
|
| + compactEncoding, functionStart);
|
| + _LIBUNWIND_ABORT("invalid compact unwind encoding");
|
| + }
|
| + savedRegisters += 4;
|
| + savedRegistersLocations = (savedRegistersLocations >> 3);
|
| + }
|
| + frameUnwind(addressSpace, registers);
|
| + return UNW_STEP_SUCCESS;
|
| +}
|
| +
|
| +template <typename A>
|
| +int CompactUnwinder_x86<A>::stepWithCompactEncodingFrameless(
|
| + compact_unwind_encoding_t encoding, uint32_t functionStart,
|
| + A &addressSpace, Registers_x86 ®isters, bool indirectStackSize) {
|
| + uint32_t stackSizeEncoded =
|
| + EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
|
| + uint32_t stackAdjust =
|
| + EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST);
|
| + uint32_t regCount =
|
| + EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
|
| + uint32_t permutation =
|
| + EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
|
| + uint32_t stackSize = stackSizeEncoded * 4;
|
| + if (indirectStackSize) {
|
| + // stack size is encoded in subl $xxx,%esp instruction
|
| + uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded);
|
| + stackSize = subl + 4 * stackAdjust;
|
| + }
|
| + // decompress permutation
|
| + uint32_t permunreg[6];
|
| + switch (regCount) {
|
| + case 6:
|
| + permunreg[0] = permutation / 120;
|
| + permutation -= (permunreg[0] * 120);
|
| + permunreg[1] = permutation / 24;
|
| + permutation -= (permunreg[1] * 24);
|
| + permunreg[2] = permutation / 6;
|
| + permutation -= (permunreg[2] * 6);
|
| + permunreg[3] = permutation / 2;
|
| + permutation -= (permunreg[3] * 2);
|
| + permunreg[4] = permutation;
|
| + permunreg[5] = 0;
|
| + break;
|
| + case 5:
|
| + permunreg[0] = permutation / 120;
|
| + permutation -= (permunreg[0] * 120);
|
| + permunreg[1] = permutation / 24;
|
| + permutation -= (permunreg[1] * 24);
|
| + permunreg[2] = permutation / 6;
|
| + permutation -= (permunreg[2] * 6);
|
| + permunreg[3] = permutation / 2;
|
| + permutation -= (permunreg[3] * 2);
|
| + permunreg[4] = permutation;
|
| + break;
|
| + case 4:
|
| + permunreg[0] = permutation / 60;
|
| + permutation -= (permunreg[0] * 60);
|
| + permunreg[1] = permutation / 12;
|
| + permutation -= (permunreg[1] * 12);
|
| + permunreg[2] = permutation / 3;
|
| + permutation -= (permunreg[2] * 3);
|
| + permunreg[3] = permutation;
|
| + break;
|
| + case 3:
|
| + permunreg[0] = permutation / 20;
|
| + permutation -= (permunreg[0] * 20);
|
| + permunreg[1] = permutation / 4;
|
| + permutation -= (permunreg[1] * 4);
|
| + permunreg[2] = permutation;
|
| + break;
|
| + case 2:
|
| + permunreg[0] = permutation / 5;
|
| + permutation -= (permunreg[0] * 5);
|
| + permunreg[1] = permutation;
|
| + break;
|
| + case 1:
|
| + permunreg[0] = permutation;
|
| + break;
|
| + }
|
| + // re-number registers back to standard numbers
|
| + int registersSaved[6];
|
| + bool used[7] = { false, false, false, false, false, false, false };
|
| + for (uint32_t i = 0; i < regCount; ++i) {
|
| + uint32_t renum = 0;
|
| + for (int u = 1; u < 7; ++u) {
|
| + if (!used[u]) {
|
| + if (renum == permunreg[i]) {
|
| + registersSaved[i] = u;
|
| + used[u] = true;
|
| + break;
|
| + }
|
| + ++renum;
|
| + }
|
| + }
|
| + }
|
| + uint32_t savedRegisters = registers.getSP() + stackSize - 4 - 4 * regCount;
|
| + for (uint32_t i = 0; i < regCount; ++i) {
|
| + switch (registersSaved[i]) {
|
| + case UNWIND_X86_REG_EBX:
|
| + registers.setEBX(addressSpace.get32(savedRegisters));
|
| + break;
|
| + case UNWIND_X86_REG_ECX:
|
| + registers.setECX(addressSpace.get32(savedRegisters));
|
| + break;
|
| + case UNWIND_X86_REG_EDX:
|
| + registers.setEDX(addressSpace.get32(savedRegisters));
|
| + break;
|
| + case UNWIND_X86_REG_EDI:
|
| + registers.setEDI(addressSpace.get32(savedRegisters));
|
| + break;
|
| + case UNWIND_X86_REG_ESI:
|
| + registers.setESI(addressSpace.get32(savedRegisters));
|
| + break;
|
| + case UNWIND_X86_REG_EBP:
|
| + registers.setEBP(addressSpace.get32(savedRegisters));
|
| + break;
|
| + default:
|
| + _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for "
|
| + "function starting at 0x%X\n",
|
| + encoding, functionStart);
|
| + _LIBUNWIND_ABORT("invalid compact unwind encoding");
|
| + }
|
| + savedRegisters += 4;
|
| + }
|
| + framelessUnwind(addressSpace, savedRegisters, registers);
|
| + return UNW_STEP_SUCCESS;
|
| +}
|
| +
|
| +
|
| +template <typename A>
|
| +void CompactUnwinder_x86<A>::frameUnwind(A &addressSpace,
|
| + Registers_x86 ®isters) {
|
| + typename A::pint_t bp = registers.getEBP();
|
| + // ebp points to old ebp
|
| + registers.setEBP(addressSpace.get32(bp));
|
| + // old esp is ebp less saved ebp and return address
|
| + registers.setSP((uint32_t)bp + 8);
|
| + // pop return address into eip
|
| + registers.setIP(addressSpace.get32(bp + 4));
|
| +}
|
| +
|
| +template <typename A>
|
| +void CompactUnwinder_x86<A>::framelessUnwind(
|
| + A &addressSpace, typename A::pint_t returnAddressLocation,
|
| + Registers_x86 ®isters) {
|
| + // return address is on stack after last saved register
|
| + registers.setIP(addressSpace.get32(returnAddressLocation));
|
| + // old esp is before return address
|
| + registers.setSP((uint32_t)returnAddressLocation + 4);
|
| +}
|
| +
|
| +
|
| +/// CompactUnwinder_x86_64 uses a compact unwind info to virtually "step" (aka
|
| +/// unwind) by modifying a Registers_x86_64 register set
|
| +template <typename A>
|
| +class CompactUnwinder_x86_64 {
|
| +public:
|
| +
|
| + static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,
|
| + uint64_t functionStart, A &addressSpace,
|
| + Registers_x86_64 ®isters);
|
| +
|
| +private:
|
| + typename A::pint_t pint_t;
|
| +
|
| + static void frameUnwind(A &addressSpace, Registers_x86_64 ®isters);
|
| + static void framelessUnwind(A &addressSpace, uint64_t returnAddressLocation,
|
| + Registers_x86_64 ®isters);
|
| + static int
|
| + stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding,
|
| + uint64_t functionStart, A &addressSpace,
|
| + Registers_x86_64 ®isters);
|
| + static int stepWithCompactEncodingFrameless(
|
| + compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
|
| + A &addressSpace, Registers_x86_64 ®isters, bool indirectStackSize);
|
| +};
|
| +
|
| +template <typename A>
|
| +int CompactUnwinder_x86_64<A>::stepWithCompactEncoding(
|
| + compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
|
| + A &addressSpace, Registers_x86_64 ®isters) {
|
| + switch (compactEncoding & UNWIND_X86_64_MODE_MASK) {
|
| + case UNWIND_X86_64_MODE_RBP_FRAME:
|
| + return stepWithCompactEncodingRBPFrame(compactEncoding, functionStart,
|
| + addressSpace, registers);
|
| + case UNWIND_X86_64_MODE_STACK_IMMD:
|
| + return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
|
| + addressSpace, registers, false);
|
| + case UNWIND_X86_64_MODE_STACK_IND:
|
| + return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
|
| + addressSpace, registers, true);
|
| + }
|
| + _LIBUNWIND_ABORT("invalid compact unwind encoding");
|
| +}
|
| +
|
| +template <typename A>
|
| +int CompactUnwinder_x86_64<A>::stepWithCompactEncodingRBPFrame(
|
| + compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
|
| + A &addressSpace, Registers_x86_64 ®isters) {
|
| + uint32_t savedRegistersOffset =
|
| + EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
|
| + uint32_t savedRegistersLocations =
|
| + EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
|
| +
|
| + uint64_t savedRegisters = registers.getRBP() - 8 * savedRegistersOffset;
|
| + for (int i = 0; i < 5; ++i) {
|
| + switch (savedRegistersLocations & 0x7) {
|
| + case UNWIND_X86_64_REG_NONE:
|
| + // no register saved in this slot
|
| + break;
|
| + case UNWIND_X86_64_REG_RBX:
|
| + registers.setRBX(addressSpace.get64(savedRegisters));
|
| + break;
|
| + case UNWIND_X86_64_REG_R12:
|
| + registers.setR12(addressSpace.get64(savedRegisters));
|
| + break;
|
| + case UNWIND_X86_64_REG_R13:
|
| + registers.setR13(addressSpace.get64(savedRegisters));
|
| + break;
|
| + case UNWIND_X86_64_REG_R14:
|
| + registers.setR14(addressSpace.get64(savedRegisters));
|
| + break;
|
| + case UNWIND_X86_64_REG_R15:
|
| + registers.setR15(addressSpace.get64(savedRegisters));
|
| + break;
|
| + default:
|
| + (void)functionStart;
|
| + _LIBUNWIND_DEBUG_LOG("bad register for RBP frame, encoding=%08X for "
|
| + "function starting at 0x%llX\n",
|
| + compactEncoding, functionStart);
|
| + _LIBUNWIND_ABORT("invalid compact unwind encoding");
|
| + }
|
| + savedRegisters += 8;
|
| + savedRegistersLocations = (savedRegistersLocations >> 3);
|
| + }
|
| + frameUnwind(addressSpace, registers);
|
| + return UNW_STEP_SUCCESS;
|
| +}
|
| +
|
| +template <typename A>
|
| +int CompactUnwinder_x86_64<A>::stepWithCompactEncodingFrameless(
|
| + compact_unwind_encoding_t encoding, uint64_t functionStart, A &addressSpace,
|
| + Registers_x86_64 ®isters, bool indirectStackSize) {
|
| + uint32_t stackSizeEncoded =
|
| + EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
|
| + uint32_t stackAdjust =
|
| + EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
|
| + uint32_t regCount =
|
| + EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
|
| + uint32_t permutation =
|
| + EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
|
| + uint32_t stackSize = stackSizeEncoded * 8;
|
| + if (indirectStackSize) {
|
| + // stack size is encoded in subl $xxx,%esp instruction
|
| + uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded);
|
| + stackSize = subl + 8 * stackAdjust;
|
| + }
|
| + // decompress permutation
|
| + uint32_t permunreg[6];
|
| + switch (regCount) {
|
| + case 6:
|
| + permunreg[0] = permutation / 120;
|
| + permutation -= (permunreg[0] * 120);
|
| + permunreg[1] = permutation / 24;
|
| + permutation -= (permunreg[1] * 24);
|
| + permunreg[2] = permutation / 6;
|
| + permutation -= (permunreg[2] * 6);
|
| + permunreg[3] = permutation / 2;
|
| + permutation -= (permunreg[3] * 2);
|
| + permunreg[4] = permutation;
|
| + permunreg[5] = 0;
|
| + break;
|
| + case 5:
|
| + permunreg[0] = permutation / 120;
|
| + permutation -= (permunreg[0] * 120);
|
| + permunreg[1] = permutation / 24;
|
| + permutation -= (permunreg[1] * 24);
|
| + permunreg[2] = permutation / 6;
|
| + permutation -= (permunreg[2] * 6);
|
| + permunreg[3] = permutation / 2;
|
| + permutation -= (permunreg[3] * 2);
|
| + permunreg[4] = permutation;
|
| + break;
|
| + case 4:
|
| + permunreg[0] = permutation / 60;
|
| + permutation -= (permunreg[0] * 60);
|
| + permunreg[1] = permutation / 12;
|
| + permutation -= (permunreg[1] * 12);
|
| + permunreg[2] = permutation / 3;
|
| + permutation -= (permunreg[2] * 3);
|
| + permunreg[3] = permutation;
|
| + break;
|
| + case 3:
|
| + permunreg[0] = permutation / 20;
|
| + permutation -= (permunreg[0] * 20);
|
| + permunreg[1] = permutation / 4;
|
| + permutation -= (permunreg[1] * 4);
|
| + permunreg[2] = permutation;
|
| + break;
|
| + case 2:
|
| + permunreg[0] = permutation / 5;
|
| + permutation -= (permunreg[0] * 5);
|
| + permunreg[1] = permutation;
|
| + break;
|
| + case 1:
|
| + permunreg[0] = permutation;
|
| + break;
|
| + }
|
| + // re-number registers back to standard numbers
|
| + int registersSaved[6];
|
| + bool used[7] = { false, false, false, false, false, false, false };
|
| + for (uint32_t i = 0; i < regCount; ++i) {
|
| + uint32_t renum = 0;
|
| + for (int u = 1; u < 7; ++u) {
|
| + if (!used[u]) {
|
| + if (renum == permunreg[i]) {
|
| + registersSaved[i] = u;
|
| + used[u] = true;
|
| + break;
|
| + }
|
| + ++renum;
|
| + }
|
| + }
|
| + }
|
| + uint64_t savedRegisters = registers.getSP() + stackSize - 8 - 8 * regCount;
|
| + for (uint32_t i = 0; i < regCount; ++i) {
|
| + switch (registersSaved[i]) {
|
| + case UNWIND_X86_64_REG_RBX:
|
| + registers.setRBX(addressSpace.get64(savedRegisters));
|
| + break;
|
| + case UNWIND_X86_64_REG_R12:
|
| + registers.setR12(addressSpace.get64(savedRegisters));
|
| + break;
|
| + case UNWIND_X86_64_REG_R13:
|
| + registers.setR13(addressSpace.get64(savedRegisters));
|
| + break;
|
| + case UNWIND_X86_64_REG_R14:
|
| + registers.setR14(addressSpace.get64(savedRegisters));
|
| + break;
|
| + case UNWIND_X86_64_REG_R15:
|
| + registers.setR15(addressSpace.get64(savedRegisters));
|
| + break;
|
| + case UNWIND_X86_64_REG_RBP:
|
| + registers.setRBP(addressSpace.get64(savedRegisters));
|
| + break;
|
| + default:
|
| + _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for "
|
| + "function starting at 0x%llX\n",
|
| + encoding, functionStart);
|
| + _LIBUNWIND_ABORT("invalid compact unwind encoding");
|
| + }
|
| + savedRegisters += 8;
|
| + }
|
| + framelessUnwind(addressSpace, savedRegisters, registers);
|
| + return UNW_STEP_SUCCESS;
|
| +}
|
| +
|
| +
|
| +template <typename A>
|
| +void CompactUnwinder_x86_64<A>::frameUnwind(A &addressSpace,
|
| + Registers_x86_64 ®isters) {
|
| + uint64_t rbp = registers.getRBP();
|
| + // ebp points to old ebp
|
| + registers.setRBP(addressSpace.get64(rbp));
|
| + // old esp is ebp less saved ebp and return address
|
| + registers.setSP(rbp + 16);
|
| + // pop return address into eip
|
| + registers.setIP(addressSpace.get64(rbp + 8));
|
| +}
|
| +
|
| +template <typename A>
|
| +void CompactUnwinder_x86_64<A>::framelessUnwind(A &addressSpace,
|
| + uint64_t returnAddressLocation,
|
| + Registers_x86_64 ®isters) {
|
| + // return address is on stack after last saved register
|
| + registers.setIP(addressSpace.get64(returnAddressLocation));
|
| + // old esp is before return address
|
| + registers.setSP(returnAddressLocation + 8);
|
| +}
|
| +
|
| +
|
| +
|
| +/// CompactUnwinder_arm64 uses a compact unwind info to virtually "step" (aka
|
| +/// unwind) by modifying a Registers_arm64 register set
|
| +template <typename A>
|
| +class CompactUnwinder_arm64 {
|
| +public:
|
| +
|
| + static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,
|
| + uint64_t functionStart, A &addressSpace,
|
| + Registers_arm64 ®isters);
|
| +
|
| +private:
|
| + typename A::pint_t pint_t;
|
| +
|
| + static int
|
| + stepWithCompactEncodingFrame(compact_unwind_encoding_t compactEncoding,
|
| + uint64_t functionStart, A &addressSpace,
|
| + Registers_arm64 ®isters);
|
| + static int stepWithCompactEncodingFrameless(
|
| + compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
|
| + A &addressSpace, Registers_arm64 ®isters);
|
| +};
|
| +
|
| +template <typename A>
|
| +int CompactUnwinder_arm64<A>::stepWithCompactEncoding(
|
| + compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
|
| + A &addressSpace, Registers_arm64 ®isters) {
|
| + switch (compactEncoding & UNWIND_ARM64_MODE_MASK) {
|
| + case UNWIND_ARM64_MODE_FRAME:
|
| + return stepWithCompactEncodingFrame(compactEncoding, functionStart,
|
| + addressSpace, registers);
|
| + case UNWIND_ARM64_MODE_FRAMELESS:
|
| + return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
|
| + addressSpace, registers);
|
| + }
|
| + _LIBUNWIND_ABORT("invalid compact unwind encoding");
|
| +}
|
| +
|
| +template <typename A>
|
| +int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrameless(
|
| + compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
|
| + Registers_arm64 ®isters) {
|
| + uint32_t stackSize =
|
| + 16 * EXTRACT_BITS(encoding, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK);
|
| +
|
| + uint64_t savedRegisterLoc = registers.getSP() + stackSize;
|
| +
|
| + if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
|
| + registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + }
|
| + if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
|
| + registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + }
|
| + if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
|
| + registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + }
|
| + if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
|
| + registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + }
|
| + if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
|
| + registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + }
|
| +
|
| + if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
|
| + registers.setFloatRegister(UNW_ARM64_D8,
|
| + addressSpace.getDouble(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + registers.setFloatRegister(UNW_ARM64_D9,
|
| + addressSpace.getDouble(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + }
|
| + if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
|
| + registers.setFloatRegister(UNW_ARM64_D10,
|
| + addressSpace.getDouble(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + registers.setFloatRegister(UNW_ARM64_D11,
|
| + addressSpace.getDouble(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + }
|
| + if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
|
| + registers.setFloatRegister(UNW_ARM64_D12,
|
| + addressSpace.getDouble(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + registers.setFloatRegister(UNW_ARM64_D13,
|
| + addressSpace.getDouble(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + }
|
| + if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
|
| + registers.setFloatRegister(UNW_ARM64_D14,
|
| + addressSpace.getDouble(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + registers.setFloatRegister(UNW_ARM64_D15,
|
| + addressSpace.getDouble(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + }
|
| +
|
| + // subtract stack size off of sp
|
| + registers.setSP(savedRegisterLoc);
|
| +
|
| + // set pc to be value in lr
|
| + registers.setIP(registers.getRegister(UNW_ARM64_LR));
|
| +
|
| + return UNW_STEP_SUCCESS;
|
| +}
|
| +
|
| +template <typename A>
|
| +int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrame(
|
| + compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
|
| + Registers_arm64 ®isters) {
|
| + uint64_t savedRegisterLoc = registers.getFP() - 8;
|
| +
|
| + if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
|
| + registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + }
|
| + if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
|
| + registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + }
|
| + if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
|
| + registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + }
|
| + if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
|
| + registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + }
|
| + if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
|
| + registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + }
|
| +
|
| + if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
|
| + registers.setFloatRegister(UNW_ARM64_D8,
|
| + addressSpace.getDouble(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + registers.setFloatRegister(UNW_ARM64_D9,
|
| + addressSpace.getDouble(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + }
|
| + if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
|
| + registers.setFloatRegister(UNW_ARM64_D10,
|
| + addressSpace.getDouble(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + registers.setFloatRegister(UNW_ARM64_D11,
|
| + addressSpace.getDouble(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + }
|
| + if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
|
| + registers.setFloatRegister(UNW_ARM64_D12,
|
| + addressSpace.getDouble(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + registers.setFloatRegister(UNW_ARM64_D13,
|
| + addressSpace.getDouble(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + }
|
| + if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
|
| + registers.setFloatRegister(UNW_ARM64_D14,
|
| + addressSpace.getDouble(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + registers.setFloatRegister(UNW_ARM64_D15,
|
| + addressSpace.getDouble(savedRegisterLoc));
|
| + savedRegisterLoc -= 8;
|
| + }
|
| +
|
| + uint64_t fp = registers.getFP();
|
| + // fp points to old fp
|
| + registers.setFP(addressSpace.get64(fp));
|
| + // old sp is fp less saved fp and lr
|
| + registers.setSP(fp + 16);
|
| + // pop return address into pc
|
| + registers.setIP(addressSpace.get64(fp + 8));
|
| +
|
| + return UNW_STEP_SUCCESS;
|
| +}
|
| +
|
| +
|
| +}; // namespace libunwind
|
| +
|
| +#endif // __COMPACT_UNWINDER_HPP__
|
|
|