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__ |