summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process/Utility/libunwind/src/CompactUnwinder.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/Process/Utility/libunwind/src/CompactUnwinder.hpp')
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/CompactUnwinder.hpp1019
1 files changed, 1019 insertions, 0 deletions
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/CompactUnwinder.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/CompactUnwinder.hpp
new file mode 100644
index 00000000000..dda2308ada6
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/CompactUnwinder.hpp
@@ -0,0 +1,1019 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- CompactUnwinder.hpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//
+// C++ interface to lower levels of libuwind
+//
+
+#ifndef __COMPACT_UNWINDER_HPP__
+#define __COMPACT_UNWINDER_HPP__
+
+#include <stdint.h>
+#include <stdio.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) )
+
+#define SUPPORT_OLD_BINARIES 0
+
+namespace lldb_private {
+
+
+
+///
+/// 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& registers);
+
+private:
+ typename A::pint_t pint_t;
+
+ static void frameUnwind(A& addressSpace, Registers_x86& registers);
+ static void framelessUnwind(A& addressSpace, typename A::pint_t returnAddressLocation, Registers_x86& registers);
+ static int stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding, uint32_t functionStart, A& addressSpace, Registers_x86& registers);
+ static int stepWithCompactEncodingFrameless(compact_unwind_encoding_t compactEncoding, uint32_t functionStart, A& addressSpace, Registers_x86& registers, bool indirectStackSize);
+#if SUPPORT_OLD_BINARIES
+ static int stepWithCompactEncodingCompat(compact_unwind_encoding_t compactEncoding, uint32_t functionStart, A& addressSpace, Registers_x86& registers);
+#endif
+};
+
+
+
+template <typename A>
+int CompactUnwinder_x86<A>::stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding, uint32_t functionStart, A& addressSpace, Registers_x86& registers)
+{
+ //fprintf(stderr, "stepWithCompactEncoding(0x%08X)\n", compactEncoding);
+ switch ( compactEncoding & UNWIND_X86_MODE_MASK ) {
+#if SUPPORT_OLD_BINARIES
+ case UNWIND_X86_MODE_COMPATIBILITY:
+ return stepWithCompactEncodingCompat(compactEncoding, functionStart, addressSpace, registers);
+#endif
+ 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);
+ }
+ 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& registers)
+{
+ uint32_t savedRegistersOffset = EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_OFFSET);
+ uint32_t savedRegistersLocations = EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_REGISTERS);
+
+ uint64_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:
+ DEBUG_MESSAGE("bad register for EBP frame, encoding=%08X for function starting at 0x%X\n", compactEncoding, functionStart);
+ 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& registers, 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
+ int 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) {
+ int 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 - 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:
+ DEBUG_MESSAGE("bad register for frameless, encoding=%08X for function starting at 0x%X\n", encoding, functionStart);
+ ABORT("invalid compact unwind encoding");
+ }
+ savedRegisters += 4;
+ }
+ framelessUnwind(addressSpace, savedRegisters, registers);
+ return UNW_STEP_SUCCESS;
+}
+
+
+#if SUPPORT_OLD_BINARIES
+template <typename A>
+int CompactUnwinder_x86<A>::stepWithCompactEncodingCompat(compact_unwind_encoding_t compactEncoding, uint32_t functionStart, A& addressSpace, Registers_x86& registers)
+{
+ //fprintf(stderr, "stepWithCompactEncoding(0x%08X)\n", compactEncoding);
+ typename A::pint_t savedRegisters;
+ uint32_t stackValue = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_SIZE);
+ uint32_t stackSize;
+ uint32_t stackAdjust;
+ switch (compactEncoding & UNWIND_X86_CASE_MASK ) {
+ case UNWIND_X86_UNWIND_INFO_UNSPECIFIED:
+ return UNW_ENOINFO;
+
+ case UNWIND_X86_EBP_FRAME_NO_REGS:
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_EBP_FRAME_EBX:
+ savedRegisters = registers.getEBP() - 4;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_EBP_FRAME_ESI:
+ savedRegisters = registers.getEBP() - 4;
+ registers.setESI(addressSpace.get32(savedRegisters));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_EBP_FRAME_EDI:
+ savedRegisters = registers.getEBP() - 4;
+ registers.setEDI(addressSpace.get32(savedRegisters));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_EBP_FRAME_EBX_ESI:
+ savedRegisters = registers.getEBP() - 8;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ registers.setESI(addressSpace.get32(savedRegisters+4));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_EBP_FRAME_ESI_EDI:
+ savedRegisters = registers.getEBP() - 8;
+ registers.setESI(addressSpace.get32(savedRegisters));
+ registers.setEDI(addressSpace.get32(savedRegisters+4));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_EBP_FRAME_EBX_ESI_EDI:
+ savedRegisters = registers.getEBP() - 12;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ registers.setESI(addressSpace.get32(savedRegisters+4));
+ registers.setEDI(addressSpace.get32(savedRegisters+8));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_EBP_FRAME_EBX_EDI:
+ savedRegisters = registers.getEBP() - 8;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ registers.setEDI(addressSpace.get32(savedRegisters+4));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IMM_STK_NO_REGS:
+ stackSize = stackValue * 4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*0;
+ framelessUnwind(addressSpace, savedRegisters+4*0, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IMM_STK_EBX:
+ stackSize = stackValue * 4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*1;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ framelessUnwind(addressSpace, savedRegisters+4*1, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IMM_STK_ESI:
+ stackSize = stackValue * 4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*1;
+ registers.setESI(addressSpace.get32(savedRegisters));
+ framelessUnwind(addressSpace, savedRegisters+4*1, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IMM_STK_EDI:
+ stackSize = stackValue * 4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*1;
+ registers.setEDI(addressSpace.get32(savedRegisters));
+ framelessUnwind(addressSpace, savedRegisters+4*1, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IMM_STK_EBX_ESI:
+ stackSize = stackValue * 4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*2;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ registers.setESI(addressSpace.get32(savedRegisters+4));
+ framelessUnwind(addressSpace, savedRegisters+4*2, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IMM_STK_ESI_EDI:
+ stackSize = stackValue * 4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*2;
+ registers.setESI(addressSpace.get32(savedRegisters));
+ registers.setEDI(addressSpace.get32(savedRegisters+4));
+ framelessUnwind(addressSpace, savedRegisters+4*2, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IMM_STK_ESI_EDI_EBP:
+ stackSize = stackValue * 4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*3;
+ registers.setESI(addressSpace.get32(savedRegisters));
+ registers.setEDI(addressSpace.get32(savedRegisters+4));
+ registers.setEBP(addressSpace.get32(savedRegisters+8));
+ framelessUnwind(addressSpace, savedRegisters+4*3, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IMM_STK_EBX_ESI_EDI:
+ stackSize = stackValue * 4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*3;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ registers.setESI(addressSpace.get32(savedRegisters+4));
+ registers.setEDI(addressSpace.get32(savedRegisters+8));
+ framelessUnwind(addressSpace, savedRegisters+4*3, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IMM_STK_EBX_ESI_EDI_EBP:
+ stackSize = stackValue * 4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*4;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ registers.setESI(addressSpace.get32(savedRegisters+4));
+ registers.setEDI(addressSpace.get32(savedRegisters+8));
+ registers.setEBP(addressSpace.get32(savedRegisters+12));
+ framelessUnwind(addressSpace, savedRegisters+4*4, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IND_STK_NO_REGS:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST);
+ stackSize += stackAdjust*4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*0;
+ framelessUnwind(addressSpace, savedRegisters+4*0, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IND_STK_EBX:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST);
+ stackSize += stackAdjust*4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*1;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ framelessUnwind(addressSpace, savedRegisters+4*1, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IND_STK_ESI:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST);
+ stackSize += stackAdjust*4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*1;
+ registers.setESI(addressSpace.get32(savedRegisters));
+ framelessUnwind(addressSpace, savedRegisters+4*1, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IND_STK_EDI:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST);
+ stackSize += stackAdjust*4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*1;
+ registers.setEDI(addressSpace.get32(savedRegisters));
+ return UNW_STEP_SUCCESS;
+ framelessUnwind(addressSpace, savedRegisters+4*1, registers);
+
+ case UNWIND_X86_IND_STK_EBX_ESI:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST);
+ stackSize += stackAdjust*4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*2;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ registers.setESI(addressSpace.get32(savedRegisters+4));
+ framelessUnwind(addressSpace, savedRegisters+4*2, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IND_STK_ESI_EDI:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST);
+ stackSize += stackAdjust*4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*2;
+ registers.setESI(addressSpace.get32(savedRegisters));
+ registers.setEDI(addressSpace.get32(savedRegisters+4));
+ framelessUnwind(addressSpace, savedRegisters+4*2, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IND_STK_ESI_EDI_EBP:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST);
+ stackSize += stackAdjust*4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*3;
+ registers.setESI(addressSpace.get32(savedRegisters));
+ registers.setEDI(addressSpace.get32(savedRegisters+4));
+ registers.setEBP(addressSpace.get32(savedRegisters+8));
+ framelessUnwind(addressSpace, savedRegisters+4*3, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IND_STK_EBX_ESI_EDI:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST);
+ stackSize += stackAdjust*4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*3;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ registers.setESI(addressSpace.get32(savedRegisters+4));
+ registers.setEDI(addressSpace.get32(savedRegisters+8));
+ framelessUnwind(addressSpace, savedRegisters+4*3, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IND_STK_EBX_ESI_EDI_EBP:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST);
+ stackSize += stackAdjust*4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*4;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ registers.setESI(addressSpace.get32(savedRegisters+4));
+ registers.setEDI(addressSpace.get32(savedRegisters+8));
+ registers.setEBP(addressSpace.get32(savedRegisters+12));
+ framelessUnwind(addressSpace, savedRegisters+4*4, registers);
+ return UNW_STEP_SUCCESS;
+
+ default:
+ DEBUG_MESSAGE("unknown compact unwind encoding %08X for function starting at 0x%X\n",
+ compactEncoding & UNWIND_X86_CASE_MASK, functionStart);
+ ABORT("unknown compact unwind encoding");
+ }
+ return UNW_EINVAL;
+}
+#endif // SUPPORT_OLD_BINARIES
+
+
+
+template <typename A>
+void CompactUnwinder_x86<A>::frameUnwind(A& addressSpace, Registers_x86& registers)
+{
+ 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(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& registers)
+{
+ // return address is on stack after last saved register
+ registers.setIP(addressSpace.get32(returnAddressLocation));
+ // old esp is before return address
+ registers.setSP(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& registers);
+
+private:
+ typename A::pint_t pint_t;
+
+ static void frameUnwind(A& addressSpace, Registers_x86_64& registers);
+ static void framelessUnwind(A& addressSpace, uint64_t returnAddressLocation, Registers_x86_64& registers);
+ static int stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A& addressSpace, Registers_x86_64& registers);
+ static int stepWithCompactEncodingFrameless(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A& addressSpace, Registers_x86_64& registers, bool indirectStackSize);
+#if SUPPORT_OLD_BINARIES
+ static int stepWithCompactEncodingCompat(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A& addressSpace, Registers_x86_64& registers);
+#endif
+};
+
+
+template <typename A>
+int CompactUnwinder_x86_64<A>::stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A& addressSpace, Registers_x86_64& registers)
+{
+ //fprintf(stderr, "stepWithCompactEncoding(0x%08X)\n", compactEncoding);
+ switch ( compactEncoding & UNWIND_X86_64_MODE_MASK ) {
+#if SUPPORT_OLD_BINARIES
+ case UNWIND_X86_64_MODE_COMPATIBILITY:
+ return stepWithCompactEncodingCompat(compactEncoding, functionStart, addressSpace, registers);
+#endif
+ 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);
+ }
+ 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& registers)
+{
+ 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) {
+ int readerr = 0;
+ 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, readerr));
+ break;
+ case UNWIND_X86_64_REG_R12:
+ registers.setR12(addressSpace.get64(savedRegisters, readerr));
+ break;
+ case UNWIND_X86_64_REG_R13:
+ registers.setR13(addressSpace.get64(savedRegisters, readerr));
+ break;
+ case UNWIND_X86_64_REG_R14:
+ registers.setR14(addressSpace.get64(savedRegisters, readerr));
+ break;
+ case UNWIND_X86_64_REG_R15:
+ registers.setR15(addressSpace.get64(savedRegisters, readerr));
+ break;
+ default:
+ DEBUG_MESSAGE("bad register for RBP frame, encoding=%08X for function starting at 0x%llX\n", compactEncoding, functionStart);
+ ABORT("invalid compact unwind encoding");
+ }
+ // Error reading memory while doing a remote unwind?
+ if (readerr)
+ return UNW_STEP_END;
+
+ 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& registers, 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
+ int 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) {
+ int 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:
+ DEBUG_MESSAGE("bad register for frameless, encoding=%08X for function starting at 0x%llX\n", encoding, functionStart);
+ ABORT("invalid compact unwind encoding");
+ }
+ savedRegisters += 8;
+ }
+ framelessUnwind(addressSpace, savedRegisters, registers);
+ return UNW_STEP_SUCCESS;
+}
+
+#if SUPPORT_OLD_BINARIES
+template <typename A>
+int CompactUnwinder_x86_64<A>::stepWithCompactEncodingCompat(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A& addressSpace, Registers_x86_64& registers)
+{
+ uint64_t savedRegisters;
+ uint32_t stackValue = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_SIZE);
+ uint64_t stackSize;
+ uint32_t stackAdjust;
+
+ switch (compactEncoding & UNWIND_X86_64_CASE_MASK ) {
+ case UNWIND_X86_64_UNWIND_INFO_UNSPECIFIED:
+ return UNW_ENOINFO;
+
+ case UNWIND_X86_64_RBP_FRAME_NO_REGS:
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_RBP_FRAME_RBX:
+ savedRegisters = registers.getRBP() - 8*1;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_RBP_FRAME_RBX_R12:
+ savedRegisters = registers.getRBP() - 8*2;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_RBP_FRAME_RBX_R12_R13:
+ savedRegisters = registers.getRBP() - 8*3;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ registers.setR13(addressSpace.get64(savedRegisters+16));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_RBP_FRAME_RBX_R12_R13_R14:
+ savedRegisters = registers.getRBP() - 8*4;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ registers.setR13(addressSpace.get64(savedRegisters+16));
+ registers.setR14(addressSpace.get64(savedRegisters+24));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_RBP_FRAME_RBX_R12_R13_R14_R15:
+ savedRegisters = registers.getRBP() - 8*5;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ registers.setR13(addressSpace.get64(savedRegisters+16));
+ registers.setR14(addressSpace.get64(savedRegisters+24));
+ registers.setR15(addressSpace.get64(savedRegisters+32));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_NO_REGS:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*0;
+ framelessUnwind(addressSpace, savedRegisters+8*0, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*1;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ framelessUnwind(addressSpace, savedRegisters+8*1, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX_R12:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*2;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ framelessUnwind(addressSpace, savedRegisters+8*2, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX_RBP:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*2;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ framelessUnwind(addressSpace, savedRegisters+8*2, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX_R12_R13:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*3;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ registers.setR13(addressSpace.get64(savedRegisters+16));
+ framelessUnwind(addressSpace, savedRegisters+8*3, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX_R12_R13_R14:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*4;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ registers.setR13(addressSpace.get64(savedRegisters+16));
+ registers.setR14(addressSpace.get64(savedRegisters+24));
+ framelessUnwind(addressSpace, savedRegisters+8*4, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX_R12_R13_R14_R15:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*5;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ registers.setR13(addressSpace.get64(savedRegisters+16));
+ registers.setR14(addressSpace.get64(savedRegisters+24));
+ registers.setR15(addressSpace.get64(savedRegisters+32));
+ framelessUnwind(addressSpace, savedRegisters+8*5, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX_RBP_R12_R13_R14_R15:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*6;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ registers.setR12(addressSpace.get64(savedRegisters+16));
+ registers.setR13(addressSpace.get64(savedRegisters+24));
+ registers.setR14(addressSpace.get64(savedRegisters+32));
+ registers.setR15(addressSpace.get64(savedRegisters+40));
+ framelessUnwind(addressSpace, savedRegisters+8*6, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX_RBP_R12:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*3;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ registers.setR12(addressSpace.get64(savedRegisters+16));
+ framelessUnwind(addressSpace, savedRegisters+8*3, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX_RBP_R12_R13:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*4;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ registers.setR12(addressSpace.get64(savedRegisters+16));
+ registers.setR13(addressSpace.get64(savedRegisters+24));
+ framelessUnwind(addressSpace, savedRegisters+8*4, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX_RBP_R12_R13_R14:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*5;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ registers.setR12(addressSpace.get64(savedRegisters+16));
+ registers.setR13(addressSpace.get64(savedRegisters+24));
+ registers.setR14(addressSpace.get64(savedRegisters+32));
+ framelessUnwind(addressSpace, savedRegisters+8*5, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_NO_REGS:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*0;
+ framelessUnwind(addressSpace, savedRegisters+8*0, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*1;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ framelessUnwind(addressSpace, savedRegisters+8*1, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX_R12:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*2;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ framelessUnwind(addressSpace, savedRegisters+8*2, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX_RBP:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*2;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ framelessUnwind(addressSpace, savedRegisters+8*2, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX_R12_R13:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*3;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ registers.setR13(addressSpace.get64(savedRegisters+16));
+ framelessUnwind(addressSpace, savedRegisters+8*3, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX_R12_R13_R14:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*4;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ registers.setR13(addressSpace.get64(savedRegisters+16));
+ registers.setR14(addressSpace.get64(savedRegisters+24));
+ framelessUnwind(addressSpace, savedRegisters+8*4, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX_R12_R13_R14_R15:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*5;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ registers.setR13(addressSpace.get64(savedRegisters+16));
+ registers.setR14(addressSpace.get64(savedRegisters+24));
+ registers.setR15(addressSpace.get64(savedRegisters+32));
+ framelessUnwind(addressSpace, savedRegisters+8*5, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX_RBP_R12_R13_R14_R15:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*6;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ registers.setR12(addressSpace.get64(savedRegisters+16));
+ registers.setR13(addressSpace.get64(savedRegisters+24));
+ registers.setR14(addressSpace.get64(savedRegisters+32));
+ registers.setR15(addressSpace.get64(savedRegisters+40));
+ framelessUnwind(addressSpace, savedRegisters+8*6, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX_RBP_R12:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*3;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ registers.setR12(addressSpace.get64(savedRegisters+16));
+ framelessUnwind(addressSpace, savedRegisters+8*3, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX_RBP_R12_R13:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*4;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ registers.setR12(addressSpace.get64(savedRegisters+16));
+ registers.setR13(addressSpace.get64(savedRegisters+24));
+ framelessUnwind(addressSpace, savedRegisters+8*4, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX_RBP_R12_R13_R14:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*5;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ registers.setR12(addressSpace.get64(savedRegisters+16));
+ registers.setR13(addressSpace.get64(savedRegisters+24));
+ registers.setR14(addressSpace.get64(savedRegisters+32));
+ framelessUnwind(addressSpace, savedRegisters+8*5, registers);
+ return UNW_STEP_SUCCESS;
+
+ default:
+ DEBUG_MESSAGE("unknown compact unwind encoding %08X for function starting at 0x%llX\n",
+ compactEncoding & UNWIND_X86_64_CASE_MASK, functionStart);
+ ABORT("unknown compact unwind encoding");
+ }
+ return UNW_EINVAL;
+}
+#endif // SUPPORT_OLD_BINARIES
+
+
+template <typename A>
+void CompactUnwinder_x86_64<A>::frameUnwind(A& addressSpace, Registers_x86_64& registers)
+{
+ 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& registers)
+{
+ // return address is on stack after last saved register
+ registers.setIP(addressSpace.get64(returnAddressLocation));
+ // old esp is before return address
+ registers.setSP(returnAddressLocation+8);
+}
+
+
+}; // namespace lldb_private
+
+
+
+#endif // __COMPACT_UNWINDER_HPP__
+
+
+
+
OpenPOWER on IntegriCloud