From 60f4ebf0203ed1c0becf8a3013e5b0c0517b11fc Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Thu, 24 Nov 2016 22:38:06 +0100 Subject: [PATCH] Use LLVM libunwind for stack unwinding on Unix This change replaces external libunwind usage on Unix by a copy of the LLVM libunwind. It also modifies libunwind to support reporting register location and implements the unw_get_save_loc API to get this location. For now, only memory locations are supported (register locations are not). --- THIRD-PARTY-NOTICES | 59 ++++ src/Native/Runtime/CMakeLists.txt | 16 +- src/Native/Runtime/startup.cpp | 6 +- src/Native/Runtime/unix/PalRedhawkUnix.cpp | 4 +- src/Native/Runtime/unix/UnixContext.cpp | 4 - src/Native/Runtime/unix/config.h.in | 1 - src/Native/Runtime/unix/configure.cmake | 6 - .../libunwind/include/__libunwind_config.h | 4 +- src/Native/libunwind/include/libunwind.h | 22 +- src/Native/libunwind/src/CompactUnwinder.hpp | 130 ++++----- .../libunwind/src/DwarfInstructions.hpp | 42 ++- src/Native/libunwind/src/Registers.hpp | 262 +++++++++++++++--- src/Native/libunwind/src/UnwindCursor.hpp | 19 +- src/Native/libunwind/src/config.h | 5 +- src/Native/libunwind/src/libunwind.cpp | 15 +- 15 files changed, 451 insertions(+), 144 deletions(-) create mode 100644 THIRD-PARTY-NOTICES diff --git a/THIRD-PARTY-NOTICES b/THIRD-PARTY-NOTICES new file mode 100644 index 00000000000..41b07973faf --- /dev/null +++ b/THIRD-PARTY-NOTICES @@ -0,0 +1,59 @@ +.NET Core uses third-party libraries or other resources that may be +distributed under licenses different than the .NET Core software. + +Attributions and licence notices for test cases originally authored by +third parties can be found in the respective test directories. + +In the event that we accidentally failed to list a required notice, please +bring it to our attention. Post an issue or email us: + + dotnet@microsoft.com + +The attached notices are provided for information only. + +License notice for The LLVM Compiler Infrastructure +--------------------------------------------------- +============================================================================== +LLVM Release License +============================================================================== +University of Illinois/NCSA +Open Source License + +Copyright (c) 2003-2015 University of Illinois at Urbana-Champaign. +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + diff --git a/src/Native/Runtime/CMakeLists.txt b/src/Native/Runtime/CMakeLists.txt index b9d3edee737..59afa5b370f 100644 --- a/src/Native/Runtime/CMakeLists.txt +++ b/src/Native/Runtime/CMakeLists.txt @@ -93,6 +93,12 @@ else() include_directories(unix) include_directories(../libunwind/include) + # Disable building _Unwind_XXX style APIs of libunwind, since we don't use them. + add_definitions(-D_LIBUNWIND_DISABLE_ZERO_COST_APIS=1) + + # Compile unwinding only for the current compilation target architecture + add_definitions(-D_LIBUNWIND_IS_NATIVE_ONLY) + list(APPEND COMMON_RUNTIME_SOURCES unix/PalRedhawkUnix.cpp ) @@ -105,6 +111,12 @@ else() ../libunwind/src/libunwind.cpp ) + if(CLR_CMAKE_PLATFORM_DARWIN) + list(APPEND FULL_RUNTIME_SOURCES + ../libunwind/src/Unwind_AppleExtras.cpp + ) + endif() + if(CLR_CMAKE_PLATFORM_ARCH_AMD64) set(ARCH_SOURCES_DIR amd64) set(ASM_SUFFIX S) @@ -117,8 +129,8 @@ else() endif() list(APPEND RUNTIME_SOURCES_ARCH_ASM - ../libunwind/src/UnwindRegistersRestore.${ASM_SUFFIX} - ../libunwind/src/UnwindRegistersSave.${ASM_SUFFIX} + ../libunwind/src/UnwindRegistersRestore.S + ../libunwind/src/UnwindRegistersSave.S ) endif() diff --git a/src/Native/Runtime/startup.cpp b/src/Native/Runtime/startup.cpp index f57e9953586..8a7b0c56cb0 100644 --- a/src/Native/Runtime/startup.cpp +++ b/src/Native/Runtime/startup.cpp @@ -70,15 +70,13 @@ bool InitDLL(HANDLE hPalInstance) if (!RestrictedCallouts::Initialize()) return false; -#ifndef USE_PORTABLE_HELPERS -#ifndef APP_LOCAL_RUNTIME +#if !defined(APP_LOCAL_RUNTIME) && !defined(USE_PORTABLE_HELPERS) #ifndef PLATFORM_UNIX PalAddVectoredExceptionHandler(1, RhpVectoredExceptionHandler); #else PalSetHardwareExceptionHandler(RhpHardwareExceptionHandler); #endif -#endif -#endif +#endif // !APP_LOCAL_RUNTIME && !USE_PORTABLE_HELPERS // // init per-instance state diff --git a/src/Native/Runtime/unix/PalRedhawkUnix.cpp b/src/Native/Runtime/unix/PalRedhawkUnix.cpp index c6798a4e988..c471b80f7e2 100644 --- a/src/Native/Runtime/unix/PalRedhawkUnix.cpp +++ b/src/Native/Runtime/unix/PalRedhawkUnix.cpp @@ -443,12 +443,12 @@ REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalInit() { return false; } -#ifndef USE_PORTABLE_HELPERS +#ifndef USE_PORTABLE_HELPERS if (!InitializeHardwareExceptionHandling()) { return false; } -#endif +#endif // !USE_PORTABLE_HELPERS int status = pthread_key_create(&g_threadKey, TlsObjectDestructor); if (status != 0) { diff --git a/src/Native/Runtime/unix/UnixContext.cpp b/src/Native/Runtime/unix/UnixContext.cpp index 944e3d98f71..02caacf8fde 100644 --- a/src/Native/Runtime/unix/UnixContext.cpp +++ b/src/Native/Runtime/unix/UnixContext.cpp @@ -11,10 +11,6 @@ #include "regdisplay.h" #include "config.h" -#if !HAVE_LIBUNWIND_H -#error Don't know how to unwind on this platform -#endif - #include #if HAVE_UCONTEXT_T diff --git a/src/Native/Runtime/unix/config.h.in b/src/Native/Runtime/unix/config.h.in index 10ad3c62f89..085ceaa3a2c 100644 --- a/src/Native/Runtime/unix/config.h.in +++ b/src/Native/Runtime/unix/config.h.in @@ -4,7 +4,6 @@ #cmakedefine01 HAVE_SYS_VMPARAM_H #cmakedefine01 HAVE_MACH_VM_TYPES_H #cmakedefine01 HAVE_MACH_VM_PARAM_H -#cmakedefine01 HAVE_LIBUNWIND_H #cmakedefine01 HAVE_PTHREAD_ATTR_GET_NP #cmakedefine01 HAVE_PTHREAD_GETATTR_NP diff --git a/src/Native/Runtime/unix/configure.cmake b/src/Native/Runtime/unix/configure.cmake index 4c0b9e97684..d58e1219ebc 100644 --- a/src/Native/Runtime/unix/configure.cmake +++ b/src/Native/Runtime/unix/configure.cmake @@ -18,7 +18,6 @@ list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_FILE_OFFSET_BITS=64) check_include_files(sys/vmparam.h HAVE_SYS_VMPARAM_H) check_include_files(mach/vm_types.h HAVE_MACH_VM_TYPES_H) check_include_files(mach/vm_param.h HAVE_MACH_VM_PARAM_H) -check_include_files(libunwind.h HAVE_LIBUNWIND_H) check_library_exists(pthread pthread_attr_get_np "" HAVE_PTHREAD_ATTR_GET_NP) check_library_exists(pthread pthread_getattr_np "" HAVE_PTHREAD_GETATTR_NP) @@ -106,9 +105,4 @@ int main() exit(ret); }" HAVE_MACH_ABSOLUTE_TIME) -if(NOT HAVE_LIBUNWIND_H) - unset(HAVE_LIBUNWIND_H CACHE) - message(FATAL_ERROR "Cannot find libunwind. Try installing libunwind8 and libunwind8-dev (or the appropriate packages for your platform)") -endif() - configure_file(${CMAKE_CURRENT_LIST_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) diff --git a/src/Native/libunwind/include/__libunwind_config.h b/src/Native/libunwind/include/__libunwind_config.h index a9d9958be05..4e363c55689 100644 --- a/src/Native/libunwind/include/__libunwind_config.h +++ b/src/Native/libunwind/include/__libunwind_config.h @@ -25,8 +25,8 @@ # define _LIBUNWIND_HIGHEST_DWARF_REGISTER 9 # elif defined(__x86_64__) # define _LIBUNWIND_TARGET_X86_64 1 -# define _LIBUNWIND_CONTEXT_SIZE 21 -# define _LIBUNWIND_CURSOR_SIZE 33 +# define _LIBUNWIND_CONTEXT_SIZE 42 +# define _LIBUNWIND_CURSOR_SIZE 54 # define _LIBUNWIND_HIGHEST_DWARF_REGISTER 17 # elif defined(__ppc__) # define _LIBUNWIND_TARGET_PPC 1 diff --git a/src/Native/libunwind/include/libunwind.h b/src/Native/libunwind/include/libunwind.h index 9d72d48d206..59187798d32 100644 --- a/src/Native/libunwind/include/libunwind.h +++ b/src/Native/libunwind/include/libunwind.h @@ -95,6 +95,26 @@ struct unw_proc_info_t { }; typedef struct unw_proc_info_t unw_proc_info_t; +enum unw_save_loc_type_t +{ + UNW_SLT_NONE, /* register is not saved ("not an l-value") */ + UNW_SLT_MEMORY, /* register has been saved in memory */ + UNW_SLT_REG /* register has been saved in (another) register */ +}; +typedef enum unw_save_loc_type_t unw_save_loc_type_t; + +struct unw_save_loc_t +{ + unw_save_loc_type_t type; + union + { + unw_word_t addr; /* valid if type==UNW_SLT_MEMORY */ + unw_regnum_t regnum; /* valid if type==UNW_SLT_REG */ + } + u; +}; +typedef struct unw_save_loc_t unw_save_loc_t; + #ifdef __cplusplus extern "C" { #endif @@ -119,7 +139,7 @@ extern int unw_get_proc_info(unw_cursor_t *, unw_proc_info_t *) LIBUNWIND_AVAIL; extern int unw_is_fpreg(unw_cursor_t *, unw_regnum_t) LIBUNWIND_AVAIL; extern int unw_is_signal_frame(unw_cursor_t *) LIBUNWIND_AVAIL; extern int unw_get_proc_name(unw_cursor_t *, char *, size_t, unw_word_t *) LIBUNWIND_AVAIL; -//extern int unw_get_save_loc(unw_cursor_t*, int, unw_save_loc_t*); +extern int unw_get_save_loc(unw_cursor_t*, int, unw_save_loc_t*); extern unw_addr_space_t unw_local_addr_space; diff --git a/src/Native/libunwind/src/CompactUnwinder.hpp b/src/Native/libunwind/src/CompactUnwinder.hpp index 1be1b0be129..84ae4247725 100644 --- a/src/Native/libunwind/src/CompactUnwinder.hpp +++ b/src/Native/libunwind/src/CompactUnwinder.hpp @@ -88,19 +88,19 @@ int CompactUnwinder_x86::stepWithCompactEncodingEBPFrame( // no register saved in this slot break; case UNWIND_X86_REG_EBX: - registers.setEBX(addressSpace.get32(savedRegisters)); + registers.setEBX(addressSpace.get32(savedRegisters), savedRegisters); break; case UNWIND_X86_REG_ECX: - registers.setECX(addressSpace.get32(savedRegisters)); + registers.setECX(addressSpace.get32(savedRegisters), savedRegisters); break; case UNWIND_X86_REG_EDX: - registers.setEDX(addressSpace.get32(savedRegisters)); + registers.setEDX(addressSpace.get32(savedRegisters), savedRegisters); break; case UNWIND_X86_REG_EDI: - registers.setEDI(addressSpace.get32(savedRegisters)); + registers.setEDI(addressSpace.get32(savedRegisters), savedRegisters); break; case UNWIND_X86_REG_ESI: - registers.setESI(addressSpace.get32(savedRegisters)); + registers.setESI(addressSpace.get32(savedRegisters), savedRegisters); break; default: (void)functionStart; @@ -205,22 +205,22 @@ int CompactUnwinder_x86::stepWithCompactEncodingFrameless( for (uint32_t i = 0; i < regCount; ++i) { switch (registersSaved[i]) { case UNWIND_X86_REG_EBX: - registers.setEBX(addressSpace.get32(savedRegisters)); + registers.setEBX(addressSpace.get32(savedRegisters), savedRegisters); break; case UNWIND_X86_REG_ECX: - registers.setECX(addressSpace.get32(savedRegisters)); + registers.setECX(addressSpace.get32(savedRegisters), savedRegisters); break; case UNWIND_X86_REG_EDX: - registers.setEDX(addressSpace.get32(savedRegisters)); + registers.setEDX(addressSpace.get32(savedRegisters), savedRegisters); break; case UNWIND_X86_REG_EDI: - registers.setEDI(addressSpace.get32(savedRegisters)); + registers.setEDI(addressSpace.get32(savedRegisters), savedRegisters); break; case UNWIND_X86_REG_ESI: - registers.setESI(addressSpace.get32(savedRegisters)); + registers.setESI(addressSpace.get32(savedRegisters), savedRegisters); break; case UNWIND_X86_REG_EBP: - registers.setEBP(addressSpace.get32(savedRegisters)); + registers.setEBP(addressSpace.get32(savedRegisters), savedRegisters); break; default: _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for " @@ -240,11 +240,11 @@ void CompactUnwinder_x86::frameUnwind(A &addressSpace, Registers_x86 ®isters) { typename A::pint_t bp = registers.getEBP(); // ebp points to old ebp - registers.setEBP(addressSpace.get32(bp)); + registers.setEBP(addressSpace.get32(bp), bp); // old esp is ebp less saved ebp and return address - registers.setSP((uint32_t)bp + 8); + registers.setSP((uint32_t)bp + 8, 0); // pop return address into eip - registers.setIP(addressSpace.get32(bp + 4)); + registers.setIP(addressSpace.get32(bp + 4), bp + 4); } template @@ -252,9 +252,9 @@ void CompactUnwinder_x86::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)); + registers.setIP(addressSpace.get32(returnAddressLocation), returnAddressLocation); // old esp is before return address - registers.setSP((uint32_t)returnAddressLocation + 4); + registers.setSP((uint32_t)returnAddressLocation + 4, 0); } #endif // _LIBUNWIND_TARGET_I386 @@ -319,19 +319,19 @@ int CompactUnwinder_x86_64::stepWithCompactEncodingRBPFrame( // no register saved in this slot break; case UNWIND_X86_64_REG_RBX: - registers.setRBX(addressSpace.get64(savedRegisters)); + registers.setRBX(addressSpace.get64(savedRegisters), savedRegisters); break; case UNWIND_X86_64_REG_R12: - registers.setR12(addressSpace.get64(savedRegisters)); + registers.setR12(addressSpace.get64(savedRegisters), savedRegisters); break; case UNWIND_X86_64_REG_R13: - registers.setR13(addressSpace.get64(savedRegisters)); + registers.setR13(addressSpace.get64(savedRegisters), savedRegisters); break; case UNWIND_X86_64_REG_R14: - registers.setR14(addressSpace.get64(savedRegisters)); + registers.setR14(addressSpace.get64(savedRegisters), savedRegisters); break; case UNWIND_X86_64_REG_R15: - registers.setR15(addressSpace.get64(savedRegisters)); + registers.setR15(addressSpace.get64(savedRegisters), savedRegisters); break; default: (void)functionStart; @@ -436,22 +436,22 @@ int CompactUnwinder_x86_64::stepWithCompactEncodingFrameless( for (uint32_t i = 0; i < regCount; ++i) { switch (registersSaved[i]) { case UNWIND_X86_64_REG_RBX: - registers.setRBX(addressSpace.get64(savedRegisters)); + registers.setRBX(addressSpace.get64(savedRegisters), savedRegisters); break; case UNWIND_X86_64_REG_R12: - registers.setR12(addressSpace.get64(savedRegisters)); + registers.setR12(addressSpace.get64(savedRegisters), savedRegisters); break; case UNWIND_X86_64_REG_R13: - registers.setR13(addressSpace.get64(savedRegisters)); + registers.setR13(addressSpace.get64(savedRegisters), savedRegisters); break; case UNWIND_X86_64_REG_R14: - registers.setR14(addressSpace.get64(savedRegisters)); + registers.setR14(addressSpace.get64(savedRegisters), savedRegisters); break; case UNWIND_X86_64_REG_R15: - registers.setR15(addressSpace.get64(savedRegisters)); + registers.setR15(addressSpace.get64(savedRegisters), savedRegisters); break; case UNWIND_X86_64_REG_RBP: - registers.setRBP(addressSpace.get64(savedRegisters)); + registers.setRBP(addressSpace.get64(savedRegisters), savedRegisters); break; default: _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for " @@ -471,11 +471,11 @@ void CompactUnwinder_x86_64::frameUnwind(A &addressSpace, Registers_x86_64 ®isters) { uint64_t rbp = registers.getRBP(); // ebp points to old ebp - registers.setRBP(addressSpace.get64(rbp)); + registers.setRBP(addressSpace.get64(rbp), rbp); // old esp is ebp less saved ebp and return address - registers.setSP(rbp + 16); + registers.setSP(rbp + 16, 0); // pop return address into eip - registers.setIP(addressSpace.get64(rbp + 8)); + registers.setIP(addressSpace.get64(rbp + 8), rbp + 8); } template @@ -483,9 +483,9 @@ void CompactUnwinder_x86_64::framelessUnwind(A &addressSpace, uint64_t returnAddressLocation, Registers_x86_64 ®isters) { // return address is on stack after last saved register - registers.setIP(addressSpace.get64(returnAddressLocation)); + registers.setIP(addressSpace.get64(returnAddressLocation), returnAddressLocation); // old esp is before return address - registers.setSP(returnAddressLocation + 8); + registers.setSP(returnAddressLocation + 8, 0); } #endif // _LIBUNWIND_TARGET_X86_64 @@ -539,74 +539,74 @@ int CompactUnwinder_arm64::stepWithCompactEncodingFrameless( uint64_t savedRegisterLoc = registers.getSP() + stackSize; if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) { - registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc)); + registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; - registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc)); + registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) { - registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc)); + registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; - registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc)); + registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) { - registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc)); + registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; - registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc)); + registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) { - registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc)); + registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; - registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc)); + registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) { - registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc)); + registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; - registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc)); + registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) { registers.setFloatRegister(UNW_ARM64_D8, - addressSpace.getDouble(savedRegisterLoc)); + addressSpace.getDouble(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; registers.setFloatRegister(UNW_ARM64_D9, - addressSpace.getDouble(savedRegisterLoc)); + addressSpace.getDouble(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) { registers.setFloatRegister(UNW_ARM64_D10, - addressSpace.getDouble(savedRegisterLoc)); + addressSpace.getDouble(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; registers.setFloatRegister(UNW_ARM64_D11, - addressSpace.getDouble(savedRegisterLoc)); + addressSpace.getDouble(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) { registers.setFloatRegister(UNW_ARM64_D12, - addressSpace.getDouble(savedRegisterLoc)); + addressSpace.getDouble(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; registers.setFloatRegister(UNW_ARM64_D13, - addressSpace.getDouble(savedRegisterLoc)); + addressSpace.getDouble(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) { registers.setFloatRegister(UNW_ARM64_D14, - addressSpace.getDouble(savedRegisterLoc)); + addressSpace.getDouble(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; registers.setFloatRegister(UNW_ARM64_D15, - addressSpace.getDouble(savedRegisterLoc)); + addressSpace.getDouble(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; } // subtract stack size off of sp - registers.setSP(savedRegisterLoc); + registers.setSP(savedRegisterLoc, 0); // set pc to be value in lr - registers.setIP(registers.getRegister(UNW_ARM64_LR)); + registers.setIP(registers.getRegister(UNW_ARM64_LR), 0); return UNW_STEP_SUCCESS; } @@ -618,33 +618,33 @@ int CompactUnwinder_arm64::stepWithCompactEncodingFrame( uint64_t savedRegisterLoc = registers.getFP() - 8; if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) { - registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc)); + registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; - registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc)); + registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) { - registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc)); + registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; - registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc)); + registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) { - registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc)); + registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; - registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc)); + registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) { - registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc)); + registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; - registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc)); + registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) { - registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc)); + registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; - registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc)); + registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc), savedRegisterLoc); savedRegisterLoc -= 8; } @@ -683,11 +683,11 @@ int CompactUnwinder_arm64::stepWithCompactEncodingFrame( uint64_t fp = registers.getFP(); // fp points to old fp - registers.setFP(addressSpace.get64(fp)); + registers.setFP(addressSpace.get64(fp), fp); // old sp is fp less saved fp and lr - registers.setSP(fp + 16); + registers.setSP(fp + 16, 0); // pop return address into pc - registers.setIP(addressSpace.get64(fp + 8)); + registers.setIP(addressSpace.get64(fp + 8), fp + 8); return UNW_STEP_SUCCESS; } diff --git a/src/Native/libunwind/src/DwarfInstructions.hpp b/src/Native/libunwind/src/DwarfInstructions.hpp index 9494bb84041..e001359d672 100644 --- a/src/Native/libunwind/src/DwarfInstructions.hpp +++ b/src/Native/libunwind/src/DwarfInstructions.hpp @@ -57,7 +57,8 @@ class DwarfInstructions { const R ®isters, pint_t initialStackValue); static pint_t getSavedRegister(A &addressSpace, const R ®isters, - pint_t cfa, const RegisterLocation &savedReg); + pint_t cfa, const RegisterLocation &savedReg, + pint_t& location); static double getSavedFloatRegister(A &addressSpace, const R ®isters, pint_t cfa, const RegisterLocation &savedReg); static v128 getSavedVectorRegister(A &addressSpace, const R ®isters, @@ -80,21 +81,24 @@ class DwarfInstructions { template typename A::pint_t DwarfInstructions::getSavedRegister( A &addressSpace, const R ®isters, pint_t cfa, - const RegisterLocation &savedReg) { + const RegisterLocation &savedReg, + typename A::pint_t& location) { switch (savedReg.location) { case CFI_Parser::kRegisterInCFA: - return addressSpace.getP(cfa + (pint_t)savedReg.value); + location = cfa + (pint_t)savedReg.value; + return addressSpace.getP(location); case CFI_Parser::kRegisterAtExpression: - return addressSpace.getP( - evaluateExpression((pint_t)savedReg.value, addressSpace, - registers, cfa)); + location = evaluateExpression((pint_t)savedReg.value, addressSpace, + registers, cfa); + return addressSpace.getP(location); case CFI_Parser::kRegisterIsExpression: + location = 0; return evaluateExpression((pint_t)savedReg.value, addressSpace, registers, cfa); - case CFI_Parser::kRegisterInRegister: + location = 0; return registers.getRegister((int)savedReg.value); case CFI_Parser::kRegisterUnused: @@ -183,13 +187,21 @@ int DwarfInstructions::stepWithDwarf(A &addressSpace, pint_t pc, newRegisters.setVectorRegister( i, getSavedVectorRegister(addressSpace, registers, cfa, prolog.savedRegisters[i])); - else if (i == (int)cieInfo.returnAddressRegister) + else if (i == (int)cieInfo.returnAddressRegister) { + pint_t dummyLocation; returnAddress = getSavedRegister(addressSpace, registers, cfa, - prolog.savedRegisters[i]); - else if (registers.validRegister(i)) - newRegisters.setRegister( - i, getSavedRegister(addressSpace, registers, cfa, - prolog.savedRegisters[i])); + prolog.savedRegisters[i], + dummyLocation); + } + else if (registers.validRegister(i)) { + pint_t value; + pint_t location; + value = getSavedRegister(addressSpace, registers, cfa, + prolog.savedRegisters[i], + location); + + newRegisters.setRegister(i, value, location); + } else return UNW_EBADREG; } @@ -197,11 +209,11 @@ int DwarfInstructions::stepWithDwarf(A &addressSpace, pint_t pc, // By definition, the CFA is the stack pointer at the call site, so // restoring SP means setting it to CFA. - newRegisters.setSP(cfa); + newRegisters.setSP(cfa, 0); // Return address is address after call site instruction, so setting IP to // that does simualates a return. - newRegisters.setIP(returnAddress); + newRegisters.setIP(returnAddress, 0); // Simulate the step by replacing the register set with the new ones. registers = newRegisters; diff --git a/src/Native/libunwind/src/Registers.hpp b/src/Native/libunwind/src/Registers.hpp index 8066b808c63..cca90092fde 100644 --- a/src/Native/libunwind/src/Registers.hpp +++ b/src/Native/libunwind/src/Registers.hpp @@ -35,7 +35,8 @@ class _LIBUNWIND_HIDDEN Registers_x86 { bool validRegister(int num) const; uint32_t getRegister(int num) const; - void setRegister(int num, uint32_t value); + void setRegister(int num, uint32_t value, uint32_t location); + uint32_t getRegisterLocation(int num) const; bool validFloatRegister(int) const { return false; } double getFloatRegister(int num) const; void setFloatRegister(int num, double value); @@ -47,21 +48,21 @@ class _LIBUNWIND_HIDDEN Registers_x86 { static int lastDwarfRegNum() { return 8; } uint32_t getSP() const { return _registers.__esp; } - void setSP(uint32_t value) { _registers.__esp = value; } + void setSP(uint32_t value, uint32_t location) { _registers.__esp = value; _registerLocations.__esp = location; } uint32_t getIP() const { return _registers.__eip; } - void setIP(uint32_t value) { _registers.__eip = value; } + void setIP(uint32_t value, uint32_t location) { _registers.__eip = value; _registerLocations.__eip = location; } uint32_t getEBP() const { return _registers.__ebp; } - void setEBP(uint32_t value) { _registers.__ebp = value; } + void setEBP(uint32_t value, uint32_t location) { _registers.__ebp = value; _registerLocations.__ebp = location; } uint32_t getEBX() const { return _registers.__ebx; } - void setEBX(uint32_t value) { _registers.__ebx = value; } + void setEBX(uint32_t value, uint32_t location) { _registers.__ebx = value; _registerLocations.__ebx = location; } uint32_t getECX() const { return _registers.__ecx; } - void setECX(uint32_t value) { _registers.__ecx = value; } + void setECX(uint32_t value, uint32_t location) { _registers.__ecx = value; _registerLocations.__ecx = location; } uint32_t getEDX() const { return _registers.__edx; } - void setEDX(uint32_t value) { _registers.__edx = value; } + void setEDX(uint32_t value, uint32_t location) { _registers.__edx = value; _registerLocations.__edx = location; } uint32_t getESI() const { return _registers.__esi; } - void setESI(uint32_t value) { _registers.__esi = value; } + void setESI(uint32_t value, uint32_t location) { _registers.__esi = value; _registerLocations.__esi = location; } uint32_t getEDI() const { return _registers.__edi; } - void setEDI(uint32_t value) { _registers.__edi = value; } + void setEDI(uint32_t value, uint32_t location) { _registers.__edi = value; _registerLocations.__edi = location; } private: struct GPRs { @@ -82,18 +83,32 @@ class _LIBUNWIND_HIDDEN Registers_x86 { unsigned int __fs; unsigned int __gs; }; + struct GPRLocations { + unsigned int __eax; + unsigned int __ebx; + unsigned int __ecx; + unsigned int __edx; + unsigned int __edi; + unsigned int __esi; + unsigned int __ebp; + unsigned int __esp; + unsigned int __eip; + }; GPRs _registers; + GPRLocations _registerLocations; }; inline Registers_x86::Registers_x86(const void *registers) { static_assert((check_fit::does_fit), "x86 registers do not fit into unw_context_t"); memcpy(&_registers, registers, sizeof(_registers)); + memset(&_registerLocations, 0, sizeof(_registerLocations)); } inline Registers_x86::Registers_x86() { memset(&_registers, 0, sizeof(_registers)); + memset(&_registerLocations, 0, sizeof(_registerLocations)); } inline bool Registers_x86::validRegister(int regNum) const { @@ -134,42 +149,78 @@ inline uint32_t Registers_x86::getRegister(int regNum) const { _LIBUNWIND_ABORT("unsupported x86 register"); } -inline void Registers_x86::setRegister(int regNum, uint32_t value) { +inline void Registers_x86::setRegister(int regNum, uint32_t value, uint32_t location) { switch (regNum) { case UNW_REG_IP: _registers.__eip = value; + _registerLocations.__eip = location; return; case UNW_REG_SP: _registers.__esp = value; + _registerLocations.__esp = location; return; case UNW_X86_EAX: _registers.__eax = value; + _registerLocations.__eax = location; return; case UNW_X86_ECX: _registers.__ecx = value; + _registerLocations.__ecx = location; return; case UNW_X86_EDX: _registers.__edx = value; + _registerLocations.__edx = location; return; case UNW_X86_EBX: _registers.__ebx = value; + _registerLocations.__ebx = location; return; case UNW_X86_EBP: _registers.__ebp = value; + _registerLocations.__ebp = location; return; case UNW_X86_ESP: _registers.__esp = value; + _registerLocations.__esp = location; return; case UNW_X86_ESI: _registers.__esi = value; + _registerLocations.__esi = location; return; case UNW_X86_EDI: _registers.__edi = value; + _registerLocations.__edi = location; return; } _LIBUNWIND_ABORT("unsupported x86 register"); } +inline uint32_t Registers_x86::getRegisterLocation(int regNum) const { + switch (regNum) { + case UNW_REG_IP: + return _registerLocations.__eip; + case UNW_REG_SP: + return _registerLocations.__esp; + case UNW_X86_EAX: + return _registerLocations.__eax; + case UNW_X86_ECX: + return _registerLocations.__ecx; + case UNW_X86_EDX: + return _registerLocations.__edx; + case UNW_X86_EBX: + return _registerLocations.__ebx; + case UNW_X86_EBP: + return _registerLocations.__ebp; + case UNW_X86_ESP: + return _registerLocations.__esp; + case UNW_X86_ESI: + return _registerLocations.__esi; + case UNW_X86_EDI: + return _registerLocations.__edi; + } + _LIBUNWIND_ABORT("unsupported x86 register"); +} + inline const char *Registers_x86::getRegisterName(int regNum) { switch (regNum) { case UNW_REG_IP: @@ -225,7 +276,8 @@ class _LIBUNWIND_HIDDEN Registers_x86_64 { bool validRegister(int num) const; uint64_t getRegister(int num) const; - void setRegister(int num, uint64_t value); + void setRegister(int num, uint64_t value, uint64_t location); + uint64_t getRegisterLocation(int num) const; bool validFloatRegister(int) const { return false; } double getFloatRegister(int num) const; void setFloatRegister(int num, double value); @@ -237,21 +289,21 @@ class _LIBUNWIND_HIDDEN Registers_x86_64 { static int lastDwarfRegNum() { return 16; } uint64_t getSP() const { return _registers.__rsp; } - void setSP(uint64_t value) { _registers.__rsp = value; } + void setSP(uint64_t value, uint64_t location) { _registers.__rsp = value; _registerLocations.__rsp = location;} uint64_t getIP() const { return _registers.__rip; } - void setIP(uint64_t value) { _registers.__rip = value; } + void setIP(uint64_t value, uint64_t location) { _registers.__rip = value; _registerLocations.__rip = location; } uint64_t getRBP() const { return _registers.__rbp; } - void setRBP(uint64_t value) { _registers.__rbp = value; } + void setRBP(uint64_t value, uint64_t location) { _registers.__rbp = value; _registerLocations.__rbp = location; } uint64_t getRBX() const { return _registers.__rbx; } - void setRBX(uint64_t value) { _registers.__rbx = value; } + void setRBX(uint64_t value, uint64_t location) { _registers.__rbx = value; _registerLocations.__rbx = location; } uint64_t getR12() const { return _registers.__r12; } - void setR12(uint64_t value) { _registers.__r12 = value; } + void setR12(uint64_t value, uint64_t location) { _registers.__r12 = value; _registerLocations.__r12 = location; } uint64_t getR13() const { return _registers.__r13; } - void setR13(uint64_t value) { _registers.__r13 = value; } + void setR13(uint64_t value, uint64_t location) { _registers.__r13 = value; _registerLocations.__r13 = location; } uint64_t getR14() const { return _registers.__r14; } - void setR14(uint64_t value) { _registers.__r14 = value; } + void setR14(uint64_t value, uint64_t location) { _registers.__r14 = value; _registerLocations.__r14 = location; } uint64_t getR15() const { return _registers.__r15; } - void setR15(uint64_t value) { _registers.__r15 = value; } + void setR15(uint64_t value, uint64_t location) { _registers.__r15 = value; _registerLocations.__r15 = location; } private: struct GPRs { @@ -277,17 +329,39 @@ class _LIBUNWIND_HIDDEN Registers_x86_64 { uint64_t __fs; uint64_t __gs; }; + struct GPRLocations { + uint64_t __rax; + uint64_t __rbx; + uint64_t __rcx; + uint64_t __rdx; + uint64_t __rdi; + uint64_t __rsi; + uint64_t __rbp; + uint64_t __rsp; + uint64_t __r8; + uint64_t __r9; + uint64_t __r10; + uint64_t __r11; + uint64_t __r12; + uint64_t __r13; + uint64_t __r14; + uint64_t __r15; + uint64_t __rip; + }; GPRs _registers; + GPRLocations _registerLocations; }; inline Registers_x86_64::Registers_x86_64(const void *registers) { static_assert((check_fit::does_fit), "x86_64 registers do not fit into unw_context_t"); memcpy(&_registers, registers, sizeof(_registers)); + memset(&_registerLocations, 0, sizeof(_registerLocations)); } inline Registers_x86_64::Registers_x86_64() { memset(&_registers, 0, sizeof(_registers)); + memset(&_registerLocations, 0, sizeof(_registerLocations)); } inline bool Registers_x86_64::validRegister(int regNum) const { @@ -344,61 +418,121 @@ inline uint64_t Registers_x86_64::getRegister(int regNum) const { _LIBUNWIND_ABORT("unsupported x86_64 register"); } -inline void Registers_x86_64::setRegister(int regNum, uint64_t value) { +inline uint64_t Registers_x86_64::getRegisterLocation(int regNum) const { + switch (regNum) { + case UNW_REG_IP: + return _registerLocations.__rip; + case UNW_REG_SP: + return _registerLocations.__rsp; + case UNW_X86_64_RAX: + return _registerLocations.__rax; + case UNW_X86_64_RDX: + return _registerLocations.__rdx; + case UNW_X86_64_RCX: + return _registerLocations.__rcx; + case UNW_X86_64_RBX: + return _registerLocations.__rbx; + case UNW_X86_64_RSI: + return _registerLocations.__rsi; + case UNW_X86_64_RDI: + return _registerLocations.__rdi; + case UNW_X86_64_RBP: + return _registerLocations.__rbp; + case UNW_X86_64_RSP: + return _registerLocations.__rsp; + case UNW_X86_64_R8: + return _registerLocations.__r8; + case UNW_X86_64_R9: + return _registerLocations.__r9; + case UNW_X86_64_R10: + return _registerLocations.__r10; + case UNW_X86_64_R11: + return _registerLocations.__r11; + case UNW_X86_64_R12: + return _registerLocations.__r12; + case UNW_X86_64_R13: + return _registerLocations.__r13; + case UNW_X86_64_R14: + return _registerLocations.__r14; + case UNW_X86_64_R15: + return _registerLocations.__r15; + } + _LIBUNWIND_ABORT("unsupported x86_64 register"); +} + +inline void Registers_x86_64::setRegister(int regNum, uint64_t value, uint64_t location) { switch (regNum) { case UNW_REG_IP: _registers.__rip = value; + _registerLocations.__rip = location; return; case UNW_REG_SP: _registers.__rsp = value; + _registerLocations.__rsp = location; return; case UNW_X86_64_RAX: _registers.__rax = value; + _registerLocations.__rax = location; return; case UNW_X86_64_RDX: _registers.__rdx = value; + _registerLocations.__rdx = location; return; case UNW_X86_64_RCX: _registers.__rcx = value; + _registerLocations.__rcx = location; return; case UNW_X86_64_RBX: _registers.__rbx = value; + _registerLocations.__rbx = location; return; case UNW_X86_64_RSI: _registers.__rsi = value; + _registerLocations.__rsi = location; return; case UNW_X86_64_RDI: _registers.__rdi = value; + _registerLocations.__rdi = location; return; case UNW_X86_64_RBP: _registers.__rbp = value; + _registerLocations.__rbp = location; return; case UNW_X86_64_RSP: _registers.__rsp = value; + _registerLocations.__rsp = location; return; case UNW_X86_64_R8: _registers.__r8 = value; + _registerLocations.__r8 = location; return; case UNW_X86_64_R9: _registers.__r9 = value; + _registerLocations.__r9 = location; return; case UNW_X86_64_R10: _registers.__r10 = value; + _registerLocations.__r10 = location; return; case UNW_X86_64_R11: _registers.__r11 = value; + _registerLocations.__r11 = location; return; case UNW_X86_64_R12: _registers.__r12 = value; + _registerLocations.__r12 = location; return; case UNW_X86_64_R13: _registers.__r13 = value; + _registerLocations.__r13 = location; return; case UNW_X86_64_R14: _registers.__r14 = value; + _registerLocations.__r14 = location; return; case UNW_X86_64_R15: _registers.__r15 = value; + _registerLocations.__r15 = location; return; } _LIBUNWIND_ABORT("unsupported x86_64 register"); @@ -1041,7 +1175,8 @@ class _LIBUNWIND_HIDDEN Registers_arm64 { bool validRegister(int num) const; uint64_t getRegister(int num) const; - void setRegister(int num, uint64_t value); + void setRegister(int num, uint64_t value, uint64_t location); + uint64_t getRegisterLocation(int num) const; bool validFloatRegister(int num) const; double getFloatRegister(int num) const; void setFloatRegister(int num, double value); @@ -1053,11 +1188,11 @@ class _LIBUNWIND_HIDDEN Registers_arm64 { static int lastDwarfRegNum() { return 95; } uint64_t getSP() const { return _registers.__sp; } - void setSP(uint64_t value) { _registers.__sp = value; } + void setSP(uint64_t value, uint64_t location) { _registers.__sp = value; _registerLocations.__sp = location; } uint64_t getIP() const { return _registers.__pc; } - void setIP(uint64_t value) { _registers.__pc = value; } + void setIP(uint64_t value, uint64_t location) { _registers.__pc = value; _registerLocations.__pc = location; } uint64_t getFP() const { return _registers.__fp; } - void setFP(uint64_t value) { _registers.__fp = value; } + void setFP(uint64_t value, uint64_t location) { _registers.__fp = value; _registerLocations.__fp = location; } private: struct GPRs { @@ -1069,8 +1204,18 @@ class _LIBUNWIND_HIDDEN Registers_arm64 { uint64_t padding; // 16-byte align }; - GPRs _registers; - double _vectorHalfRegisters[32]; + struct GPRLocations { + uint64_t __x[29]; // x0-x28 + uint64_t __fp; // Frame pointer x29 + uint64_t __lr; // Link register x30 + uint64_t __sp; // Stack pointer x31 + uint64_t __pc; // Program counter + uint64_t padding; // 16-byte align + }; + + GPRs _registers; + GPRLocations _registerLocations; + double _vectorHalfRegisters[32]; // Currently only the lower double in 128-bit vectore registers // is perserved during unwinding. We could define new register // numbers (> 96) which mean whole vector registers, then this @@ -1081,6 +1226,7 @@ inline Registers_arm64::Registers_arm64(const void *registers) { static_assert((check_fit::does_fit), "arm64 registers do not fit into unw_context_t"); memcpy(&_registers, registers, sizeof(_registers)); + memset(&_registerLocations, 0, sizeof(_registerLocations)); static_assert(sizeof(GPRs) == 0x110, "expected VFP registers to be at offset 272"); memcpy(_vectorHalfRegisters, @@ -1090,6 +1236,7 @@ inline Registers_arm64::Registers_arm64(const void *registers) { inline Registers_arm64::Registers_arm64() { memset(&_registers, 0, sizeof(_registers)); + memset(&_registerLocations, 0, sizeof(_registerLocations)); memset(&_vectorHalfRegisters, 0, sizeof(_vectorHalfRegisters)); } @@ -1117,17 +1264,33 @@ inline uint64_t Registers_arm64::getRegister(int regNum) const { _LIBUNWIND_ABORT("unsupported arm64 register"); } -inline void Registers_arm64::setRegister(int regNum, uint64_t value) { - if (regNum == UNW_REG_IP) +inline void Registers_arm64::setRegister(int regNum, uint64_t value, uint64_t location) { + if (regNum == UNW_REG_IP) { _registers.__pc = value; - else if (regNum == UNW_REG_SP) + _registerLocations.__pc = location; + } + else if (regNum == UNW_REG_SP) { _registers.__sp = value; - else if ((regNum >= 0) && (regNum < 32)) + _registerLocations.__sp = location; + } + else if ((regNum >= 0) && (regNum < 32)) { _registers.__x[regNum] = value; + _registerLocations.__x[regNum] = location; + } else _LIBUNWIND_ABORT("unsupported arm64 register"); } +inline uint64_t Registers_arm64::getRegisterLocation(int regNum) const { + if (regNum == UNW_REG_IP) + return _registerLocations.__pc; + if (regNum == UNW_REG_SP) + return _registerLocations.__sp; + if ((regNum >= 0) && (regNum < 32)) + return _registerLocations.__x[regNum]; + _LIBUNWIND_ABORT("unsupported arm64 register"); +} + inline const char *Registers_arm64::getRegisterName(int regNum) { switch (regNum) { case UNW_REG_IP: @@ -1311,7 +1474,8 @@ class _LIBUNWIND_HIDDEN Registers_arm { bool validRegister(int num) const; uint32_t getRegister(int num); - void setRegister(int num, uint32_t value); + void setRegister(int num, uint32_t value, uint32_t location); + uint32_t getRegisterLocation(int num) const; bool validFloatRegister(int num) const; unw_fpreg_t getFloatRegister(int num); void setFloatRegister(int num, unw_fpreg_t value); @@ -1325,9 +1489,9 @@ class _LIBUNWIND_HIDDEN Registers_arm { } uint32_t getSP() const { return _registers.__sp; } - void setSP(uint32_t value) { _registers.__sp = value; } + void setSP(uint32_t value, uint32_t location) { _registers.__sp = value; _registerLocations.__sp = location; } uint32_t getIP() const { return _registers.__pc; } - void setIP(uint32_t value) { _registers.__pc = value; } + void setIP(uint32_t value, uint32_t location) { _registers.__pc = value; _registerLocations.__pc = location; } void saveVFPAsX() { assert(_use_X_for_vfp_save || !_saved_vfp_d0_d15); @@ -1359,6 +1523,13 @@ class _LIBUNWIND_HIDDEN Registers_arm { uint32_t __pc; // Program counter r15 }; + struct GPRLocations { + uint32_t __r[13]; // r0-r12 + uint32_t __sp; // Stack pointer r13 + uint32_t __lr; // Link register r14 + uint32_t __pc; // Program counter r15 + }; + static void saveVFPWithFSTMD(unw_fpreg_t*); static void saveVFPWithFSTMX(unw_fpreg_t*); static void saveVFPv3(unw_fpreg_t*); @@ -1375,6 +1546,7 @@ class _LIBUNWIND_HIDDEN Registers_arm { // ARM registers GPRs _registers; + GPRLocations _registerLocations; // We save floating point registers lazily because we can't know ahead of // time which ones are used. See EHABI #4.7. @@ -1412,6 +1584,7 @@ inline Registers_arm::Registers_arm(const void *registers) "arm registers do not fit into unw_context_t"); // See unw_getcontext() note about data. memcpy(&_registers, registers, sizeof(_registers)); + memset(&_registerLocations, 0, sizeof(_registerLocations)); memset(&_vfp_d0_d15_pad, 0, sizeof(_vfp_d0_d15_pad)); memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31)); #if defined(__ARM_WMMX) @@ -1427,6 +1600,7 @@ inline Registers_arm::Registers_arm() _saved_vfp_d0_d15(false), _saved_vfp_d16_d31(false) { memset(&_registers, 0, sizeof(_registers)); + memset(&_registerLocations, 0, sizeof(_registerLocations)); memset(&_vfp_d0_d15_pad, 0, sizeof(_vfp_d0_d15_pad)); memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31)); #if defined(__ARM_WMMX) @@ -1483,24 +1657,28 @@ inline uint32_t Registers_arm::getRegister(int regNum) { _LIBUNWIND_ABORT("unsupported arm register"); } -inline void Registers_arm::setRegister(int regNum, uint32_t value) { +inline void Registers_arm::setRegister(int regNum, uint32_t value, uint32_t location) { if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP) { _registers.__sp = value; + _registerLocations.__sp = location; return; } if (regNum == UNW_ARM_LR) { _registers.__lr = value; + _registerLocations.__lr = location; return; } if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP) { _registers.__pc = value; + _registerLocations.__pc = location; return; } if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R12) { _registers.__r[regNum] = value; + _registerLocations.__r[regNum] = location; return; } @@ -1518,6 +1696,22 @@ inline void Registers_arm::setRegister(int regNum, uint32_t value) { _LIBUNWIND_ABORT("unsupported arm register"); } +inline uint32_t Registers_arm::getRegisterLocation(int regNum) const { + if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP) + return _registerLocations.__sp; + + if (regNum == UNW_ARM_LR) + return _registerLocations.__lr; + + if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP) + return _registerLocations.__pc; + + if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R12) + return _registerLocations.__r[regNum]; + + _LIBUNWIND_ABORT("unsupported arm register"); +} + inline const char *Registers_arm::getRegisterName(int regNum) { switch (regNum) { case UNW_REG_IP: diff --git a/src/Native/libunwind/src/UnwindCursor.hpp b/src/Native/libunwind/src/UnwindCursor.hpp index 4ed5a6ec069..7a1149eaf67 100644 --- a/src/Native/libunwind/src/UnwindCursor.hpp +++ b/src/Native/libunwind/src/UnwindCursor.hpp @@ -384,9 +384,12 @@ class _LIBUNWIND_HIDDEN AbstractUnwindCursor { virtual ~AbstractUnwindCursor() {} virtual bool validReg(int) { _LIBUNWIND_ABORT("validReg not implemented"); } virtual unw_word_t getReg(int) { _LIBUNWIND_ABORT("getReg not implemented"); } - virtual void setReg(int, unw_word_t) { + virtual void setReg(int, unw_word_t, unw_word_t) { _LIBUNWIND_ABORT("setReg not implemented"); } + virtual unw_word_t getRegLocation(int) { + _LIBUNWIND_ABORT("getRegLocation not implemented"); + } virtual bool validFloatReg(int) { _LIBUNWIND_ABORT("validFloatReg not implemented"); } @@ -429,7 +432,8 @@ class UnwindCursor : public AbstractUnwindCursor{ virtual ~UnwindCursor() {} virtual bool validReg(int); virtual unw_word_t getReg(int); - virtual void setReg(int, unw_word_t); + virtual void setReg(int, unw_word_t, unw_word_t); + virtual unw_word_t getRegLocation(int); virtual bool validFloatReg(int); virtual unw_fpreg_t getFloatReg(int); virtual void setFloatReg(int, unw_fpreg_t); @@ -634,8 +638,13 @@ unw_word_t UnwindCursor::getReg(int regNum) { } template -void UnwindCursor::setReg(int regNum, unw_word_t value) { - _registers.setRegister(regNum, (typename A::pint_t)value); +void UnwindCursor::setReg(int regNum, unw_word_t value, unw_word_t location) { + _registers.setRegister(regNum, (typename A::pint_t)value, (typename A::pint_t)location); +} + +template +unw_word_t UnwindCursor::getRegLocation(int regNum) { + return _registers.getRegisterLocation(regNum); } template @@ -1349,7 +1358,7 @@ int UnwindCursor::step() { if (_unwindInfoMissing) return UNW_STEP_END; if (_info.gp) - setReg(UNW_REG_SP, getReg(UNW_REG_SP) + _info.gp); + setReg(UNW_REG_SP, getReg(UNW_REG_SP) + _info.gp, 0); } return result; diff --git a/src/Native/libunwind/src/config.h b/src/Native/libunwind/src/config.h index 4e4dd997a03..bba0f9c9f1f 100644 --- a/src/Native/libunwind/src/config.h +++ b/src/Native/libunwind/src/config.h @@ -68,11 +68,12 @@ #define _LIBUNWIND_SUPPORT_FRAME_APIS 0 #endif -#if defined(__i386__) || defined(__x86_64__) || \ +#if !_LIBUNWIND_DISABLE_ZERO_COST_APIS && ( \ + defined(__i386__) || defined(__x86_64__) || \ defined(__ppc__) || defined(__ppc64__) || \ (!defined(__APPLE__) && defined(__arm__)) || \ (defined(__arm64__) || defined(__aarch64__)) || \ - (defined(__APPLE__) && defined(__mips__)) + (defined(__APPLE__) && defined(__mips__))) #define _LIBUNWIND_BUILD_ZERO_COST_APIS 1 #else #define _LIBUNWIND_BUILD_ZERO_COST_APIS 0 diff --git a/src/Native/libunwind/src/libunwind.cpp b/src/Native/libunwind/src/libunwind.cpp index bbb829eedd4..c9e3ba15a78 100644 --- a/src/Native/libunwind/src/libunwind.cpp +++ b/src/Native/libunwind/src/libunwind.cpp @@ -177,7 +177,7 @@ _LIBUNWIND_EXPORT int unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum, typedef LocalAddressSpace::pint_t pint_t; AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; if (co->validReg(regNum)) { - co->setReg(regNum, (pint_t)value); + co->setReg(regNum, (pint_t)value, 0); // specical case altering IP to re-find info (being called by personality // function) if (regNum == UNW_REG_IP) @@ -221,6 +221,19 @@ _LIBUNWIND_EXPORT int unw_set_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum, return UNW_EBADREG; } +/// Get location of specified register at cursor position in stack frame. +_LIBUNWIND_EXPORT int unw_get_save_loc(unw_cursor_t* cursor, int regNum, + unw_save_loc_t* location) +{ + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + if (co->validReg(regNum)) { + // We only support memory locations, not register locations + location->u.addr = co->getRegLocation(regNum); + location->type = (location->u.addr == 0) ? UNW_SLT_NONE : UNW_SLT_MEMORY; + return UNW_ESUCCESS; + } + return UNW_EBADREG; +} /// Move cursor to next frame. _LIBUNWIND_EXPORT int unw_step(unw_cursor_t *cursor) {