diff options
Diffstat (limited to 'lldb/source/Plugins/Process/Utility/libunwind/src/CompactUnwinder.hpp')
-rw-r--r-- | lldb/source/Plugins/Process/Utility/libunwind/src/CompactUnwinder.hpp | 1019 |
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__ + + + + |