From 8ef57cf97cea96f88139ced9dfaa80f1049144cb Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Fri, 8 Mar 2019 22:14:20 +0000 Subject: [PATCH 01/18] Vendor import of LLVM libunwind trunk r351319 (just before the release_80 branch point): https://llvm.org/svn/llvm-project/libunwind/trunk@351319 --- LICENSE.TXT | 76 + include/__libunwind_config.h | 112 +- include/libunwind.h | 352 ++++- include/mach-o/compact_unwind_encoding.h | 32 +- include/unwind.h | 59 +- src/AddressSpace.hpp | 382 +++-- src/CompactUnwinder.hpp | 9 +- src/DwarfInstructions.hpp | 55 +- src/DwarfParser.hpp | 338 +++-- src/EHHeaderParser.hpp | 7 +- src/RWMutex.hpp | 77 + src/Registers.hpp | 1719 +++++++++++++++++++++- src/Unwind-EHABI.cpp | 164 ++- src/Unwind-EHABI.h | 4 +- src/Unwind-seh.cpp | 491 ++++++ src/Unwind-sjlj.c | 138 +- src/UnwindCursor.hpp | 721 ++++++++- src/UnwindLevel1-gcc-ext.c | 88 +- src/UnwindLevel1.c | 109 +- src/UnwindRegistersRestore.S | 567 ++++++- src/UnwindRegistersSave.S | 582 +++++++- src/Unwind_AppleExtras.cpp | 31 +- src/assembly.h | 60 +- src/config.h | 128 +- src/dwarf2.h | 5 +- src/libunwind.cpp | 95 +- src/libunwind_ext.h | 2 +- src/unwind_ext.h | 37 - 28 files changed, 5569 insertions(+), 871 deletions(-) create mode 100644 LICENSE.TXT create mode 100644 src/RWMutex.hpp create mode 100644 src/Unwind-seh.cpp delete mode 100644 src/unwind_ext.h diff --git a/LICENSE.TXT b/LICENSE.TXT new file mode 100644 index 00000000000..23109b4aa7b --- /dev/null +++ b/LICENSE.TXT @@ -0,0 +1,76 @@ +============================================================================== +libunwind License +============================================================================== + +The libunwind library is dual licensed under both the University of Illinois +"BSD-Like" license and the MIT license. As a user of this code you may choose +to use it under either license. As a contributor, you agree to allow your code +to be used under both. + +Full text of the relevant licenses is included below. + +============================================================================== + +University of Illinois/NCSA +Open Source License + +Copyright (c) 2009-2019 by the contributors listed in CREDITS.TXT + +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. + +============================================================================== + +Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in 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: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +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 +AUTHORS 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 IN +THE SOFTWARE. diff --git a/include/__libunwind_config.h b/include/__libunwind_config.h index 099d133e744..a8e30de13a6 100644 --- a/include/__libunwind_config.h +++ b/include/__libunwind_config.h @@ -12,48 +12,130 @@ #if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \ !defined(__ARM_DWARF_EH__) -#define _LIBUNWIND_ARM_EHABI 1 -#else -#define _LIBUNWIND_ARM_EHABI 0 +#define _LIBUNWIND_ARM_EHABI #endif +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86 8 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64 32 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC 112 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64 116 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64 95 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM 287 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K 32 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS 65 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC 31 + #if defined(_LIBUNWIND_IS_NATIVE_ONLY) # if defined(__i386__) -# define _LIBUNWIND_TARGET_I386 1 +# define _LIBUNWIND_TARGET_I386 # define _LIBUNWIND_CONTEXT_SIZE 8 -# define _LIBUNWIND_CURSOR_SIZE 19 +# define _LIBUNWIND_CURSOR_SIZE 15 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86 # elif defined(__x86_64__) # define _LIBUNWIND_TARGET_X86_64 1 -# define _LIBUNWIND_CONTEXT_SIZE 21 -# define _LIBUNWIND_CURSOR_SIZE 33 +# if defined(_WIN64) +# define _LIBUNWIND_CONTEXT_SIZE 54 +# ifdef __SEH__ +# define _LIBUNWIND_CURSOR_SIZE 204 +# else +# define _LIBUNWIND_CURSOR_SIZE 66 +# endif +# else +# define _LIBUNWIND_CONTEXT_SIZE 21 +# define _LIBUNWIND_CURSOR_SIZE 33 +# endif +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64 +# elif defined(__powerpc64__) +# define _LIBUNWIND_TARGET_PPC64 1 +# define _LIBUNWIND_CONTEXT_SIZE 167 +# define _LIBUNWIND_CURSOR_SIZE 179 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64 # elif defined(__ppc__) # define _LIBUNWIND_TARGET_PPC 1 # define _LIBUNWIND_CONTEXT_SIZE 117 -# define _LIBUNWIND_CURSOR_SIZE 128 +# define _LIBUNWIND_CURSOR_SIZE 124 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC # elif defined(__aarch64__) # define _LIBUNWIND_TARGET_AARCH64 1 # define _LIBUNWIND_CONTEXT_SIZE 66 -# define _LIBUNWIND_CURSOR_SIZE 78 +# if defined(__SEH__) +# define _LIBUNWIND_CURSOR_SIZE 164 +# else +# define _LIBUNWIND_CURSOR_SIZE 78 +# endif +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64 # elif defined(__arm__) # define _LIBUNWIND_TARGET_ARM 1 -# define _LIBUNWIND_CONTEXT_SIZE 60 -# define _LIBUNWIND_CURSOR_SIZE 67 +# if defined(__SEH__) +# define _LIBUNWIND_CONTEXT_SIZE 42 +# define _LIBUNWIND_CURSOR_SIZE 80 +# elif defined(__ARM_WMMX) +# define _LIBUNWIND_CONTEXT_SIZE 61 +# define _LIBUNWIND_CURSOR_SIZE 68 +# else +# define _LIBUNWIND_CONTEXT_SIZE 42 +# define _LIBUNWIND_CURSOR_SIZE 49 +# endif +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM # elif defined(__or1k__) # define _LIBUNWIND_TARGET_OR1K 1 # define _LIBUNWIND_CONTEXT_SIZE 16 -# define _LIBUNWIND_CURSOR_SIZE 28 +# define _LIBUNWIND_CURSOR_SIZE 24 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K +# elif defined(__mips__) +# if defined(_ABIO32) && _MIPS_SIM == _ABIO32 +# define _LIBUNWIND_TARGET_MIPS_O32 1 +# if defined(__mips_hard_float) +# define _LIBUNWIND_CONTEXT_SIZE 50 +# define _LIBUNWIND_CURSOR_SIZE 57 +# else +# define _LIBUNWIND_CONTEXT_SIZE 18 +# define _LIBUNWIND_CURSOR_SIZE 24 +# endif +# elif defined(_ABIN32) && _MIPS_SIM == _ABIN32 +# define _LIBUNWIND_TARGET_MIPS_NEWABI 1 +# if defined(__mips_hard_float) +# define _LIBUNWIND_CONTEXT_SIZE 67 +# define _LIBUNWIND_CURSOR_SIZE 74 +# else +# define _LIBUNWIND_CONTEXT_SIZE 35 +# define _LIBUNWIND_CURSOR_SIZE 42 +# endif +# elif defined(_ABI64) && _MIPS_SIM == _ABI64 +# define _LIBUNWIND_TARGET_MIPS_NEWABI 1 +# if defined(__mips_hard_float) +# define _LIBUNWIND_CONTEXT_SIZE 67 +# define _LIBUNWIND_CURSOR_SIZE 79 +# else +# define _LIBUNWIND_CONTEXT_SIZE 35 +# define _LIBUNWIND_CURSOR_SIZE 47 +# endif +# else +# error "Unsupported MIPS ABI and/or environment" +# endif +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS +# elif defined(__sparc__) + #define _LIBUNWIND_TARGET_SPARC 1 + #define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC + #define _LIBUNWIND_CONTEXT_SIZE 16 + #define _LIBUNWIND_CURSOR_SIZE 23 # else # error "Unsupported architecture." # endif #else // !_LIBUNWIND_IS_NATIVE_ONLY -# define _LIBUNWIND_TARGET_I386 1 +# define _LIBUNWIND_TARGET_I386 # define _LIBUNWIND_TARGET_X86_64 1 # define _LIBUNWIND_TARGET_PPC 1 +# define _LIBUNWIND_TARGET_PPC64 1 # define _LIBUNWIND_TARGET_AARCH64 1 # define _LIBUNWIND_TARGET_ARM 1 # define _LIBUNWIND_TARGET_OR1K 1 -# define _LIBUNWIND_CONTEXT_SIZE 128 -# define _LIBUNWIND_CURSOR_SIZE 140 +# define _LIBUNWIND_TARGET_MIPS_O32 1 +# define _LIBUNWIND_TARGET_MIPS_NEWABI 1 +# define _LIBUNWIND_TARGET_SPARC 1 +# define _LIBUNWIND_CONTEXT_SIZE 167 +# define _LIBUNWIND_CURSOR_SIZE 179 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287 #endif // _LIBUNWIND_IS_NATIVE_ONLY #endif // ____LIBUNWIND_CONFIG_H__ diff --git a/include/libunwind.h b/include/libunwind.h index c5b9633b150..29c4aebde5a 100644 --- a/include/libunwind.h +++ b/include/libunwind.h @@ -6,7 +6,7 @@ // Source Licenses. See LICENSE.TXT for details. // // -// Compatible with libuwind API documented at: +// Compatible with libunwind API documented at: // http://www.nongnu.org/libunwind/man/libunwind(3).html // //===----------------------------------------------------------------------===// @@ -20,12 +20,26 @@ #include #ifdef __APPLE__ - #include - #ifdef __arm__ - #define LIBUNWIND_AVAIL __attribute__((unavailable)) - #else - #define LIBUNWIND_AVAIL __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_5_0) + #if __clang__ + #if __has_include() + #include #endif + #elif __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050 + #include + #endif + + #ifdef __arm__ + #define LIBUNWIND_AVAIL __attribute__((unavailable)) + #elif defined(__OSX_AVAILABLE_STARTING) + #define LIBUNWIND_AVAIL __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_5_0) + #else + #include + #ifdef AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER + #define LIBUNWIND_AVAIL AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER + #else + #define LIBUNWIND_AVAIL __attribute__((unavailable)) + #endif + #endif #else #define LIBUNWIND_AVAIL #endif @@ -43,6 +57,9 @@ enum { UNW_EINVAL = -6547, /* unsupported operation or bad value */ UNW_EBADVERSION = -6548, /* unwind info has unsupported version */ UNW_ENOINFO = -6549 /* no unwind info found */ +#if defined(_LIBUNWIND_TARGET_AARCH64) && !defined(_LIBUNWIND_IS_NATIVE_ONLY) + , UNW_ECROSSRASIGNING = -6550 /* cross unwind with return address signing */ +#endif }; struct unw_context_t { @@ -58,11 +75,10 @@ typedef struct unw_cursor_t unw_cursor_t; typedef struct unw_addr_space *unw_addr_space_t; typedef int unw_regnum_t; -#if _LIBUNWIND_ARM_EHABI -typedef uint32_t unw_word_t; +typedef uintptr_t unw_word_t; +#if defined(__arm__) typedef uint64_t unw_fpreg_t; #else -typedef uint64_t unw_word_t; typedef double unw_fpreg_t; #endif @@ -75,8 +91,8 @@ struct unw_proc_info_t { unw_word_t gp; /* not used */ unw_word_t flags; /* not used */ uint32_t format; /* compact unwind encoding, or zero if none */ - uint32_t unwind_info_size; /* size of dwarf unwind info, or zero if none */ - unw_word_t unwind_info; /* address of dwarf unwind info, or zero */ + uint32_t unwind_info_size; /* size of DWARF unwind info, or zero if none */ + unw_word_t unwind_info; /* address of DWARF unwind info, or zero */ unw_word_t extra; /* mach_header of mach-o image containing func */ }; typedef struct unw_proc_info_t unw_proc_info_t; @@ -120,7 +136,7 @@ extern int unw_init_remote_thread(unw_cursor_t *, unw_addr_space_t, thread_t *); #endif /* UNW_REMOTE */ /* - * traditional libuwind "remote" API + * traditional libunwind "remote" API * NOT IMPLEMENTED on Mac OS X * * extern int unw_init_remote(unw_cursor_t*, unw_addr_space_t, @@ -174,7 +190,24 @@ enum { UNW_X86_64_R12 = 12, UNW_X86_64_R13 = 13, UNW_X86_64_R14 = 14, - UNW_X86_64_R15 = 15 + UNW_X86_64_R15 = 15, + UNW_X86_64_RIP = 16, + UNW_X86_64_XMM0 = 17, + UNW_X86_64_XMM1 = 18, + UNW_X86_64_XMM2 = 19, + UNW_X86_64_XMM3 = 20, + UNW_X86_64_XMM4 = 21, + UNW_X86_64_XMM5 = 22, + UNW_X86_64_XMM6 = 23, + UNW_X86_64_XMM7 = 24, + UNW_X86_64_XMM8 = 25, + UNW_X86_64_XMM9 = 26, + UNW_X86_64_XMM10 = 27, + UNW_X86_64_XMM11 = 28, + UNW_X86_64_XMM12 = 29, + UNW_X86_64_XMM13 = 30, + UNW_X86_64_XMM14 = 31, + UNW_X86_64_XMM15 = 32, }; @@ -295,6 +328,190 @@ enum { UNW_PPC_SPEFSCR = 112 }; +// 64-bit ppc register numbers +enum { + UNW_PPC64_R0 = 0, + UNW_PPC64_R1 = 1, + UNW_PPC64_R2 = 2, + UNW_PPC64_R3 = 3, + UNW_PPC64_R4 = 4, + UNW_PPC64_R5 = 5, + UNW_PPC64_R6 = 6, + UNW_PPC64_R7 = 7, + UNW_PPC64_R8 = 8, + UNW_PPC64_R9 = 9, + UNW_PPC64_R10 = 10, + UNW_PPC64_R11 = 11, + UNW_PPC64_R12 = 12, + UNW_PPC64_R13 = 13, + UNW_PPC64_R14 = 14, + UNW_PPC64_R15 = 15, + UNW_PPC64_R16 = 16, + UNW_PPC64_R17 = 17, + UNW_PPC64_R18 = 18, + UNW_PPC64_R19 = 19, + UNW_PPC64_R20 = 20, + UNW_PPC64_R21 = 21, + UNW_PPC64_R22 = 22, + UNW_PPC64_R23 = 23, + UNW_PPC64_R24 = 24, + UNW_PPC64_R25 = 25, + UNW_PPC64_R26 = 26, + UNW_PPC64_R27 = 27, + UNW_PPC64_R28 = 28, + UNW_PPC64_R29 = 29, + UNW_PPC64_R30 = 30, + UNW_PPC64_R31 = 31, + UNW_PPC64_F0 = 32, + UNW_PPC64_F1 = 33, + UNW_PPC64_F2 = 34, + UNW_PPC64_F3 = 35, + UNW_PPC64_F4 = 36, + UNW_PPC64_F5 = 37, + UNW_PPC64_F6 = 38, + UNW_PPC64_F7 = 39, + UNW_PPC64_F8 = 40, + UNW_PPC64_F9 = 41, + UNW_PPC64_F10 = 42, + UNW_PPC64_F11 = 43, + UNW_PPC64_F12 = 44, + UNW_PPC64_F13 = 45, + UNW_PPC64_F14 = 46, + UNW_PPC64_F15 = 47, + UNW_PPC64_F16 = 48, + UNW_PPC64_F17 = 49, + UNW_PPC64_F18 = 50, + UNW_PPC64_F19 = 51, + UNW_PPC64_F20 = 52, + UNW_PPC64_F21 = 53, + UNW_PPC64_F22 = 54, + UNW_PPC64_F23 = 55, + UNW_PPC64_F24 = 56, + UNW_PPC64_F25 = 57, + UNW_PPC64_F26 = 58, + UNW_PPC64_F27 = 59, + UNW_PPC64_F28 = 60, + UNW_PPC64_F29 = 61, + UNW_PPC64_F30 = 62, + UNW_PPC64_F31 = 63, + // 64: reserved + UNW_PPC64_LR = 65, + UNW_PPC64_CTR = 66, + // 67: reserved + UNW_PPC64_CR0 = 68, + UNW_PPC64_CR1 = 69, + UNW_PPC64_CR2 = 70, + UNW_PPC64_CR3 = 71, + UNW_PPC64_CR4 = 72, + UNW_PPC64_CR5 = 73, + UNW_PPC64_CR6 = 74, + UNW_PPC64_CR7 = 75, + UNW_PPC64_XER = 76, + UNW_PPC64_V0 = 77, + UNW_PPC64_V1 = 78, + UNW_PPC64_V2 = 79, + UNW_PPC64_V3 = 80, + UNW_PPC64_V4 = 81, + UNW_PPC64_V5 = 82, + UNW_PPC64_V6 = 83, + UNW_PPC64_V7 = 84, + UNW_PPC64_V8 = 85, + UNW_PPC64_V9 = 86, + UNW_PPC64_V10 = 87, + UNW_PPC64_V11 = 88, + UNW_PPC64_V12 = 89, + UNW_PPC64_V13 = 90, + UNW_PPC64_V14 = 91, + UNW_PPC64_V15 = 92, + UNW_PPC64_V16 = 93, + UNW_PPC64_V17 = 94, + UNW_PPC64_V18 = 95, + UNW_PPC64_V19 = 96, + UNW_PPC64_V20 = 97, + UNW_PPC64_V21 = 98, + UNW_PPC64_V22 = 99, + UNW_PPC64_V23 = 100, + UNW_PPC64_V24 = 101, + UNW_PPC64_V25 = 102, + UNW_PPC64_V26 = 103, + UNW_PPC64_V27 = 104, + UNW_PPC64_V28 = 105, + UNW_PPC64_V29 = 106, + UNW_PPC64_V30 = 107, + UNW_PPC64_V31 = 108, + // 109, 111-113: OpenPOWER ELF V2 ABI: reserved + // Borrowing VRSAVE number from PPC32. + UNW_PPC64_VRSAVE = 109, + UNW_PPC64_VSCR = 110, + UNW_PPC64_TFHAR = 114, + UNW_PPC64_TFIAR = 115, + UNW_PPC64_TEXASR = 116, + UNW_PPC64_VS0 = UNW_PPC64_F0, + UNW_PPC64_VS1 = UNW_PPC64_F1, + UNW_PPC64_VS2 = UNW_PPC64_F2, + UNW_PPC64_VS3 = UNW_PPC64_F3, + UNW_PPC64_VS4 = UNW_PPC64_F4, + UNW_PPC64_VS5 = UNW_PPC64_F5, + UNW_PPC64_VS6 = UNW_PPC64_F6, + UNW_PPC64_VS7 = UNW_PPC64_F7, + UNW_PPC64_VS8 = UNW_PPC64_F8, + UNW_PPC64_VS9 = UNW_PPC64_F9, + UNW_PPC64_VS10 = UNW_PPC64_F10, + UNW_PPC64_VS11 = UNW_PPC64_F11, + UNW_PPC64_VS12 = UNW_PPC64_F12, + UNW_PPC64_VS13 = UNW_PPC64_F13, + UNW_PPC64_VS14 = UNW_PPC64_F14, + UNW_PPC64_VS15 = UNW_PPC64_F15, + UNW_PPC64_VS16 = UNW_PPC64_F16, + UNW_PPC64_VS17 = UNW_PPC64_F17, + UNW_PPC64_VS18 = UNW_PPC64_F18, + UNW_PPC64_VS19 = UNW_PPC64_F19, + UNW_PPC64_VS20 = UNW_PPC64_F20, + UNW_PPC64_VS21 = UNW_PPC64_F21, + UNW_PPC64_VS22 = UNW_PPC64_F22, + UNW_PPC64_VS23 = UNW_PPC64_F23, + UNW_PPC64_VS24 = UNW_PPC64_F24, + UNW_PPC64_VS25 = UNW_PPC64_F25, + UNW_PPC64_VS26 = UNW_PPC64_F26, + UNW_PPC64_VS27 = UNW_PPC64_F27, + UNW_PPC64_VS28 = UNW_PPC64_F28, + UNW_PPC64_VS29 = UNW_PPC64_F29, + UNW_PPC64_VS30 = UNW_PPC64_F30, + UNW_PPC64_VS31 = UNW_PPC64_F31, + UNW_PPC64_VS32 = UNW_PPC64_V0, + UNW_PPC64_VS33 = UNW_PPC64_V1, + UNW_PPC64_VS34 = UNW_PPC64_V2, + UNW_PPC64_VS35 = UNW_PPC64_V3, + UNW_PPC64_VS36 = UNW_PPC64_V4, + UNW_PPC64_VS37 = UNW_PPC64_V5, + UNW_PPC64_VS38 = UNW_PPC64_V6, + UNW_PPC64_VS39 = UNW_PPC64_V7, + UNW_PPC64_VS40 = UNW_PPC64_V8, + UNW_PPC64_VS41 = UNW_PPC64_V9, + UNW_PPC64_VS42 = UNW_PPC64_V10, + UNW_PPC64_VS43 = UNW_PPC64_V11, + UNW_PPC64_VS44 = UNW_PPC64_V12, + UNW_PPC64_VS45 = UNW_PPC64_V13, + UNW_PPC64_VS46 = UNW_PPC64_V14, + UNW_PPC64_VS47 = UNW_PPC64_V15, + UNW_PPC64_VS48 = UNW_PPC64_V16, + UNW_PPC64_VS49 = UNW_PPC64_V17, + UNW_PPC64_VS50 = UNW_PPC64_V18, + UNW_PPC64_VS51 = UNW_PPC64_V19, + UNW_PPC64_VS52 = UNW_PPC64_V20, + UNW_PPC64_VS53 = UNW_PPC64_V21, + UNW_PPC64_VS54 = UNW_PPC64_V22, + UNW_PPC64_VS55 = UNW_PPC64_V23, + UNW_PPC64_VS56 = UNW_PPC64_V24, + UNW_PPC64_VS57 = UNW_PPC64_V25, + UNW_PPC64_VS58 = UNW_PPC64_V26, + UNW_PPC64_VS59 = UNW_PPC64_V27, + UNW_PPC64_VS60 = UNW_PPC64_V28, + UNW_PPC64_VS61 = UNW_PPC64_V29, + UNW_PPC64_VS62 = UNW_PPC64_V30, + UNW_PPC64_VS63 = UNW_PPC64_V31 +}; + // 64-bit ARM64 registers enum { UNW_ARM64_X0 = 0, @@ -333,6 +550,8 @@ enum { UNW_ARM64_X31 = 31, UNW_ARM64_SP = 31, // reserved block + UNW_ARM64_RA_SIGN_STATE = 34, + // reserved block UNW_ARM64_D0 = 64, UNW_ARM64_D1 = 65, UNW_ARM64_D2 = 66, @@ -531,6 +750,113 @@ enum { UNW_OR1K_R29 = 29, UNW_OR1K_R30 = 30, UNW_OR1K_R31 = 31, + UNW_OR1K_EPCR = 32, +}; + +// MIPS registers +enum { + UNW_MIPS_R0 = 0, + UNW_MIPS_R1 = 1, + UNW_MIPS_R2 = 2, + UNW_MIPS_R3 = 3, + UNW_MIPS_R4 = 4, + UNW_MIPS_R5 = 5, + UNW_MIPS_R6 = 6, + UNW_MIPS_R7 = 7, + UNW_MIPS_R8 = 8, + UNW_MIPS_R9 = 9, + UNW_MIPS_R10 = 10, + UNW_MIPS_R11 = 11, + UNW_MIPS_R12 = 12, + UNW_MIPS_R13 = 13, + UNW_MIPS_R14 = 14, + UNW_MIPS_R15 = 15, + UNW_MIPS_R16 = 16, + UNW_MIPS_R17 = 17, + UNW_MIPS_R18 = 18, + UNW_MIPS_R19 = 19, + UNW_MIPS_R20 = 20, + UNW_MIPS_R21 = 21, + UNW_MIPS_R22 = 22, + UNW_MIPS_R23 = 23, + UNW_MIPS_R24 = 24, + UNW_MIPS_R25 = 25, + UNW_MIPS_R26 = 26, + UNW_MIPS_R27 = 27, + UNW_MIPS_R28 = 28, + UNW_MIPS_R29 = 29, + UNW_MIPS_R30 = 30, + UNW_MIPS_R31 = 31, + UNW_MIPS_F0 = 32, + UNW_MIPS_F1 = 33, + UNW_MIPS_F2 = 34, + UNW_MIPS_F3 = 35, + UNW_MIPS_F4 = 36, + UNW_MIPS_F5 = 37, + UNW_MIPS_F6 = 38, + UNW_MIPS_F7 = 39, + UNW_MIPS_F8 = 40, + UNW_MIPS_F9 = 41, + UNW_MIPS_F10 = 42, + UNW_MIPS_F11 = 43, + UNW_MIPS_F12 = 44, + UNW_MIPS_F13 = 45, + UNW_MIPS_F14 = 46, + UNW_MIPS_F15 = 47, + UNW_MIPS_F16 = 48, + UNW_MIPS_F17 = 49, + UNW_MIPS_F18 = 50, + UNW_MIPS_F19 = 51, + UNW_MIPS_F20 = 52, + UNW_MIPS_F21 = 53, + UNW_MIPS_F22 = 54, + UNW_MIPS_F23 = 55, + UNW_MIPS_F24 = 56, + UNW_MIPS_F25 = 57, + UNW_MIPS_F26 = 58, + UNW_MIPS_F27 = 59, + UNW_MIPS_F28 = 60, + UNW_MIPS_F29 = 61, + UNW_MIPS_F30 = 62, + UNW_MIPS_F31 = 63, + UNW_MIPS_HI = 64, + UNW_MIPS_LO = 65, +}; + +// SPARC registers +enum { + UNW_SPARC_G0 = 0, + UNW_SPARC_G1 = 1, + UNW_SPARC_G2 = 2, + UNW_SPARC_G3 = 3, + UNW_SPARC_G4 = 4, + UNW_SPARC_G5 = 5, + UNW_SPARC_G6 = 6, + UNW_SPARC_G7 = 7, + UNW_SPARC_O0 = 8, + UNW_SPARC_O1 = 9, + UNW_SPARC_O2 = 10, + UNW_SPARC_O3 = 11, + UNW_SPARC_O4 = 12, + UNW_SPARC_O5 = 13, + UNW_SPARC_O6 = 14, + UNW_SPARC_O7 = 15, + UNW_SPARC_L0 = 16, + UNW_SPARC_L1 = 17, + UNW_SPARC_L2 = 18, + UNW_SPARC_L3 = 19, + UNW_SPARC_L4 = 20, + UNW_SPARC_L5 = 21, + UNW_SPARC_L6 = 22, + UNW_SPARC_L7 = 23, + UNW_SPARC_I0 = 24, + UNW_SPARC_I1 = 25, + UNW_SPARC_I2 = 26, + UNW_SPARC_I3 = 27, + UNW_SPARC_I4 = 28, + UNW_SPARC_I5 = 29, + UNW_SPARC_I6 = 30, + UNW_SPARC_I7 = 31, }; #endif diff --git a/include/mach-o/compact_unwind_encoding.h b/include/mach-o/compact_unwind_encoding.h index b71c2c8f5b7..de14fd51e53 100644 --- a/include/mach-o/compact_unwind_encoding.h +++ b/include/mach-o/compact_unwind_encoding.h @@ -6,7 +6,7 @@ // Source Licenses. See LICENSE.TXT for details. // // -// Darwin's alternative to dwarf based unwind encodings. +// Darwin's alternative to DWARF based unwind encodings. // //===----------------------------------------------------------------------===// @@ -17,7 +17,7 @@ #include // -// Compilers can emit standard Dwarf FDEs in the __TEXT,__eh_frame section +// Compilers can emit standard DWARF FDEs in the __TEXT,__eh_frame section // of object files. Or compilers can emit compact unwind information in // the __LD,__compact_unwind section. // @@ -26,10 +26,10 @@ // runtime to access unwind info for any given function. If the compiler // emitted compact unwind info for the function, that compact unwind info will // be encoded in the __TEXT,__unwind_info section. If the compiler emitted -// dwarf unwind info, the __TEXT,__unwind_info section will contain the offset +// DWARF unwind info, the __TEXT,__unwind_info section will contain the offset // of the FDE in the __TEXT,__eh_frame section in the final linked image. // -// Note: Previously, the linker would transform some dwarf unwind infos into +// Note: Previously, the linker would transform some DWARF unwind infos into // compact unwind info. But that is fragile and no longer done. @@ -58,7 +58,7 @@ enum { // 1-bit: has lsda // 2-bit: personality index // -// 4-bits: 0=old, 1=ebp based, 2=stack-imm, 3=stack-ind, 4=dwarf +// 4-bits: 0=old, 1=ebp based, 2=stack-imm, 3=stack-ind, 4=DWARF // ebp based: // 15-bits (5*3-bits per reg) register permutation // 8-bits for stack offset @@ -128,9 +128,9 @@ enum { // UNWIND_X86_FRAMELESS_STACK_SIZE. // UNWIND_X86_MODE_DWARF: // No compact unwind encoding is available. Instead the low 24-bits of the -// compact encoding is the offset of the dwarf FDE in the __eh_frame section. +// compact encoding is the offset of the DWARF FDE in the __eh_frame section. // This mode is never used in object files. It is only generated by the -// linker in final linked images which have only dwarf unwind info for a +// linker in final linked images which have only DWARF unwind info for a // function. // // The permutation encoding is a Lehmer code sequence encoded into a @@ -193,7 +193,7 @@ enum { // 1-bit: has lsda // 2-bit: personality index // -// 4-bits: 0=old, 1=rbp based, 2=stack-imm, 3=stack-ind, 4=dwarf +// 4-bits: 0=old, 1=rbp based, 2=stack-imm, 3=stack-ind, 4=DWARF // rbp based: // 15-bits (5*3-bits per reg) register permutation // 8-bits for stack offset @@ -262,9 +262,9 @@ enum { // UNWIND_X86_64_FRAMELESS_STACK_SIZE. // UNWIND_X86_64_MODE_DWARF: // No compact unwind encoding is available. Instead the low 24-bits of the -// compact encoding is the offset of the dwarf FDE in the __eh_frame section. +// compact encoding is the offset of the DWARF FDE in the __eh_frame section. // This mode is never used in object files. It is only generated by the -// linker in final linked images which have only dwarf unwind info for a +// linker in final linked images which have only DWARF unwind info for a // function. // @@ -275,14 +275,14 @@ enum { // 1-bit: has lsda // 2-bit: personality index // -// 4-bits: 4=frame-based, 3=dwarf, 2=frameless +// 4-bits: 4=frame-based, 3=DWARF, 2=frameless // frameless: // 12-bits of stack size // frame-based: // 4-bits D reg pairs saved // 5-bits X reg pairs saved -// dwarf: -// 24-bits offset of dwarf FDE in __eh_frame section +// DWARF: +// 24-bits offset of DWARF FDE in __eh_frame section // enum { UNWIND_ARM64_MODE_MASK = 0x0F000000, @@ -320,9 +320,9 @@ enum { // UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK. // UNWIND_ARM64_MODE_DWARF: // No compact unwind encoding is available. Instead the low 24-bits of the -// compact encoding is the offset of the dwarf FDE in the __eh_frame section. +// compact encoding is the offset of the DWARF FDE in the __eh_frame section. // This mode is never used in object files. It is only generated by the -// linker in final linked images which have only dwarf unwind info for a +// linker in final linked images which have only DWARF unwind info for a // function. // @@ -385,7 +385,7 @@ enum { // saved at that range of the function. // // If a particular function is so wacky that there is no compact unwind way -// to encode it, then the compiler can emit traditional dwarf unwind info. +// to encode it, then the compiler can emit traditional DWARF unwind info. // The runtime will use which ever is available. // // Runtime support for compact unwind encodings are only available on 10.6 diff --git a/include/unwind.h b/include/unwind.h index 94880bfebae..ae8ae5d24ed 100644 --- a/include/unwind.h +++ b/include/unwind.h @@ -19,6 +19,11 @@ #include #include +#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) && defined(_WIN32) +#include +#include +#endif + #if defined(__APPLE__) #define LIBUNWIND_UNAVAIL __attribute__ (( unavailable )) #else @@ -36,7 +41,7 @@ typedef enum { _URC_HANDLER_FOUND = 6, _URC_INSTALL_CONTEXT = 7, _URC_CONTINUE_UNWIND = 8, -#if _LIBUNWIND_ARM_EHABI +#if defined(_LIBUNWIND_ARM_EHABI) _URC_FAILURE = 9 #endif } _Unwind_Reason_Code; @@ -51,12 +56,13 @@ typedef enum { typedef struct _Unwind_Context _Unwind_Context; // opaque -#if _LIBUNWIND_ARM_EHABI +#if defined(_LIBUNWIND_ARM_EHABI) typedef uint32_t _Unwind_State; static const _Unwind_State _US_VIRTUAL_UNWIND_FRAME = 0; static const _Unwind_State _US_UNWIND_FRAME_STARTING = 1; static const _Unwind_State _US_UNWIND_FRAME_RESUME = 2; +static const _Unwind_State _US_ACTION_MASK = 3; /* Undocumented flag for force unwinding. */ static const _Unwind_State _US_FORCE_UNWIND = 8; @@ -99,7 +105,7 @@ struct _Unwind_Control_Block { } pr_cache; long long int :0; /* Enforce the 8-byte alignment */ -}; +} __attribute__((__aligned__(8))); typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) (_Unwind_State state, @@ -119,16 +125,23 @@ struct _Unwind_Exception { uint64_t exception_class; void (*exception_cleanup)(_Unwind_Reason_Code reason, _Unwind_Exception *exc); +#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) + uintptr_t private_[6]; +#else uintptr_t private_1; // non-zero means forced unwind uintptr_t private_2; // holds sp that phase1 found for phase2 to use -#ifndef __LP64__ - // The gcc implementation of _Unwind_Exception used attribute mode on the - // above fields which had the side effect of causing this whole struct to - // round up to 32 bytes in size. To be more explicit, we add pad fields - // added for binary compatibility. +#endif +#if __SIZEOF_POINTER__ == 4 + // The implementation of _Unwind_Exception uses an attribute mode on the + // above fields which has the side effect of causing this whole struct to + // round up to 32 bytes in size (48 with SEH). To be more explicit, we add + // pad fields added for binary compatibility. uint32_t reserved[3]; #endif -}; + // The Itanium ABI requires that _Unwind_Exception objects are "double-word + // aligned". GCC has interpreted this to mean "use the maximum useful + // alignment for the target"; so do we. +} __attribute__((__aligned__)); typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) (int version, @@ -164,7 +177,7 @@ extern void _Unwind_Resume(_Unwind_Exception *exception_object); #endif extern void _Unwind_DeleteException(_Unwind_Exception *exception_object); -#if _LIBUNWIND_ARM_EHABI +#if defined(_LIBUNWIND_ARM_EHABI) typedef enum { _UVRSC_CORE = 0, /* integer register */ _UVRSC_VFP = 1, /* vfp */ @@ -204,7 +217,7 @@ _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, _Unwind_VRS_DataRepresentation representation); #endif -#if !_LIBUNWIND_ARM_EHABI +#if !defined(_LIBUNWIND_ARM_EHABI) extern uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index); extern void _Unwind_SetGR(struct _Unwind_Context *context, int index, @@ -212,7 +225,7 @@ extern void _Unwind_SetGR(struct _Unwind_Context *context, int index, extern uintptr_t _Unwind_GetIP(struct _Unwind_Context *context); extern void _Unwind_SetIP(struct _Unwind_Context *, uintptr_t new_value); -#else // _LIBUNWIND_ARM_EHABI +#else // defined(_LIBUNWIND_ARM_EHABI) #if defined(_LIBUNWIND_UNWIND_LEVEL1_EXTERNAL_LINKAGE) #define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 extern @@ -251,7 +264,7 @@ void _Unwind_SetIP(struct _Unwind_Context *context, uintptr_t value) { uintptr_t thumb_bit = _Unwind_GetGR(context, 15) & ((uintptr_t)0x1); _Unwind_SetGR(context, 15, value | thumb_bit); } -#endif // _LIBUNWIND_ARM_EHABI +#endif // defined(_LIBUNWIND_ARM_EHABI) extern uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context *context); extern uintptr_t @@ -321,7 +334,7 @@ extern void __deregister_frame(const void *fde); // _Unwind_Find_FDE() will locate the FDE if the pc is in some function that has // an associated FDE. Note, Mac OS X 10.6 and later, introduces "compact unwind -// info" which the runtime uses in preference to dwarf unwind info. This +// info" which the runtime uses in preference to DWARF unwind info. This // function will only work if the target function has an FDE but no compact // unwind info. struct dwarf_eh_bases { @@ -334,7 +347,7 @@ extern const void *_Unwind_Find_FDE(const void *pc, struct dwarf_eh_bases *); // This function attempts to find the start (address of first instruction) of // a function given an address inside the function. It only works if the -// function has an FDE (dwarf unwind info). +// function has an FDE (DWARF unwind info). // This function is unimplemented on Mac OS X 10.6 and later. Instead, use // _Unwind_Find_FDE() and look at the dwarf_eh_bases.func result. extern void *_Unwind_FindEnclosingFunction(void *pc); @@ -365,6 +378,22 @@ extern void *__deregister_frame_info(const void *fde) extern void *__deregister_frame_info_bases(const void *fde) LIBUNWIND_UNAVAIL; +#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) +#ifndef _WIN32 +typedef struct _EXCEPTION_RECORD EXCEPTION_RECORD; +typedef struct _CONTEXT CONTEXT; +typedef struct _DISPATCHER_CONTEXT DISPATCHER_CONTEXT; +#elif !defined(__MINGW32__) && VER_PRODUCTBUILD < 8000 +typedef struct _DISPATCHER_CONTEXT DISPATCHER_CONTEXT; +#endif +// This is the common wrapper for GCC-style personality functions with SEH. +extern EXCEPTION_DISPOSITION _GCC_specific_handler(EXCEPTION_RECORD *exc, + void *frame, + CONTEXT *ctx, + DISPATCHER_CONTEXT *disp, + __personality_routine pers); +#endif + #ifdef __cplusplus } #endif diff --git a/src/AddressSpace.hpp b/src/AddressSpace.hpp index da1b6a43e49..30ad35995ae 100644 --- a/src/AddressSpace.hpp +++ b/src/AddressSpace.hpp @@ -18,7 +18,15 @@ #include #include -#ifndef _LIBUNWIND_IS_BAREMETAL +#ifndef _LIBUNWIND_USE_DLADDR + #if !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32) + #define _LIBUNWIND_USE_DLADDR 1 + #else + #define _LIBUNWIND_USE_DLADDR 0 + #endif +#endif + +#if _LIBUNWIND_USE_DLADDR #include #endif @@ -32,72 +40,137 @@ namespace libunwind { #include "libunwind.h" #include "config.h" #include "dwarf2.h" +#include "EHHeaderParser.hpp" #include "Registers.hpp" -#if _LIBUNWIND_ARM_EHABI -#if defined(__FreeBSD__) || defined(__NetBSD__) +#ifdef __APPLE__ -typedef void *_Unwind_Ptr; + struct dyld_unwind_sections + { + const struct mach_header* mh; + const void* dwarf_section; + uintptr_t dwarf_section_length; + const void* compact_unwind_section; + uintptr_t compact_unwind_section_length; + }; + #if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \ + && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) \ + || defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + // In 10.7.0 or later, libSystem.dylib implements this function. + extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *); + #else + // In 10.6.x and earlier, we need to implement this functionality. Note + // that this requires a newer version of libmacho (from cctools) than is + // present in libSystem on 10.6.x (for getsectiondata). + static inline bool _dyld_find_unwind_sections(void* addr, + dyld_unwind_sections* info) { + // Find mach-o image containing address. + Dl_info dlinfo; + if (!dladdr(addr, &dlinfo)) + return false; +#if __LP64__ + const struct mach_header_64 *mh = (const struct mach_header_64 *)dlinfo.dli_fbase; +#else + const struct mach_header *mh = (const struct mach_header *)dlinfo.dli_fbase; +#endif -#elif defined(__linux__) + // Initialize the return struct + info->mh = (const struct mach_header *)mh; + info->dwarf_section = getsectiondata(mh, "__TEXT", "__eh_frame", &info->dwarf_section_length); + info->compact_unwind_section = getsectiondata(mh, "__TEXT", "__unwind_info", &info->compact_unwind_section_length); -typedef long unsigned int *_Unwind_Ptr; -extern "C" _Unwind_Ptr __gnu_Unwind_Find_exidx(_Unwind_Ptr addr, int *len); + if (!info->dwarf_section) { + info->dwarf_section_length = 0; + } -// Emulate the BSD dl_unwind_find_exidx API when on a GNU libdl system. -#define dl_unwind_find_exidx __gnu_Unwind_Find_exidx + if (!info->compact_unwind_section) { + info->compact_unwind_section_length = 0; + } + + return true; + } + #endif + +#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL) -#elif !defined(_LIBUNWIND_IS_BAREMETAL) -#include -#else // !defined(_LIBUNWIND_IS_BAREMETAL) // When statically linked on bare-metal, the symbols for the EH table are looked // up without going through the dynamic loader. -struct EHTEntry { - uint32_t functionOffset; - uint32_t unwindOpcodes; -}; -extern EHTEntry __exidx_start; -extern EHTEntry __exidx_end; -#endif // !defined(_LIBUNWIND_IS_BAREMETAL) -#endif // _LIBUNWIND_ARM_EHABI -#if defined(__CloudABI__) || defined(__FreeBSD__) || defined(__linux__) || \ - defined(__NetBSD__) -#if _LIBUNWIND_SUPPORT_DWARF_UNWIND && _LIBUNWIND_SUPPORT_DWARF_INDEX +// The following linker script may be used to produce the necessary sections and symbols. +// Unless the --eh-frame-hdr linker option is provided, the section is not generated +// and does not take space in the output file. +// +// .eh_frame : +// { +// __eh_frame_start = .; +// KEEP(*(.eh_frame)) +// __eh_frame_end = .; +// } +// +// .eh_frame_hdr : +// { +// KEEP(*(.eh_frame_hdr)) +// } +// +// __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0; +// __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0; + +extern char __eh_frame_start; +extern char __eh_frame_end; + +#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) +extern char __eh_frame_hdr_start; +extern char __eh_frame_hdr_end; +#endif + +#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL) + +// When statically linked on bare-metal, the symbols for the EH table are looked +// up without going through the dynamic loader. +extern char __exidx_start; +extern char __exidx_end; + +#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + +// ELF-based systems may use dl_iterate_phdr() to access sections +// containing unwinding information. The ElfW() macro for pointer-size +// independent ELF header traversal is not provided by on some +// systems (e.g., FreeBSD). On these systems the data structures are +// just called Elf_XXX. Define ElfW() locally. +#ifndef _WIN32 #include -// Macro for machine-independent access to the ELF program headers. This -// macro is not available on some systems (e.g., FreeBSD). On these -// systems the data structures are just called Elf_XXX. Define ElfW() -// locally. +#else +#include +#include +#endif #if !defined(ElfW) #define ElfW(type) Elf_##type #endif -#include "EHHeaderParser.hpp" -#endif + #endif namespace libunwind { /// Used by findUnwindSections() to return info about needed sections. struct UnwindInfoSections { -#if _LIBUNWIND_SUPPORT_DWARF_UNWIND || _LIBUNWIND_SUPPORT_DWARF_INDEX || \ - _LIBUNWIND_SUPPORT_COMPACT_UNWIND - // No dso_base for ARM EHABI. +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) || \ + defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) + // No dso_base for SEH or ARM EHABI. uintptr_t dso_base; #endif -#if _LIBUNWIND_SUPPORT_DWARF_UNWIND +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) uintptr_t dwarf_section; uintptr_t dwarf_section_length; #endif -#if _LIBUNWIND_SUPPORT_DWARF_INDEX +#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) uintptr_t dwarf_index_section; uintptr_t dwarf_index_section_length; #endif -#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND +#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) uintptr_t compact_unwind_section; uintptr_t compact_unwind_section_length; #endif -#if _LIBUNWIND_ARM_EHABI +#if defined(_LIBUNWIND_ARM_EHABI) uintptr_t arm_section; uintptr_t arm_section_length; #endif @@ -107,15 +180,10 @@ struct UnwindInfoSections { /// LocalAddressSpace is used as a template parameter to UnwindCursor when /// unwinding a thread in the same process. The wrappers compile away, /// making local unwinds fast. -class __attribute__((visibility("hidden"))) LocalAddressSpace { +class _LIBUNWIND_HIDDEN LocalAddressSpace { public: -#ifdef __LP64__ - typedef uint64_t pint_t; - typedef int64_t sint_t; -#else - typedef uint32_t pint_t; - typedef int32_t sint_t; -#endif + typedef uintptr_t pint_t; + typedef intptr_t sint_t; uint8_t get8(pint_t addr) { uint8_t val; memcpy(&val, (void *)addr, sizeof(val)); @@ -147,6 +215,7 @@ class __attribute__((visibility("hidden"))) LocalAddressSpace { return val; } uintptr_t getP(pint_t addr); + uint64_t getRegister(pint_t addr); static uint64_t getULEB128(pint_t &addr, pint_t end); static int64_t getSLEB128(pint_t &addr, pint_t end); @@ -161,7 +230,15 @@ class __attribute__((visibility("hidden"))) LocalAddressSpace { }; inline uintptr_t LocalAddressSpace::getP(pint_t addr) { -#ifdef __LP64__ +#if __SIZEOF_POINTER__ == 8 + return get64(addr); +#else + return get32(addr); +#endif +} + +inline uint64_t LocalAddressSpace::getRegister(pint_t addr) { +#if __SIZEOF_POINTER__ == 8 || defined(__mips64) return get64(addr); #else return get32(addr); @@ -209,7 +286,7 @@ inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) { } while (byte & 0x80); // sign extend negative numbers if ((byte & 0x40) != 0) - result |= (-1LL) << bit; + result |= (-1ULL) << bit; addr = (pint_t) p; return result; } @@ -306,55 +383,13 @@ LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, return result; } -#ifdef __APPLE__ - struct dyld_unwind_sections - { - const struct mach_header* mh; - const void* dwarf_section; - uintptr_t dwarf_section_length; - const void* compact_unwind_section; - uintptr_t compact_unwind_section_length; - }; - #if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \ - && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) \ - || defined(__IPHONE_OS_VERSION_MIN_REQUIRED) - // In 10.7.0 or later, libSystem.dylib implements this function. - extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *); - #else - // In 10.6.x and earlier, we need to implement this functionality. - static inline bool _dyld_find_unwind_sections(void* addr, - dyld_unwind_sections* info) { - // Find mach-o image containing address. - Dl_info dlinfo; - if (!dladdr(addr, &dlinfo)) - return false; - const mach_header *mh = (const mach_header *)dlinfo.dli_saddr; - - // Find dwarf unwind section in that image. - unsigned long size; - const uint8_t *p = getsectiondata(mh, "__TEXT", "__eh_frame", &size); - if (!p) - return false; - - // Fill in return struct. - info->mh = mh; - info->dwarf_section = p; - info->dwarf_section_length = size; - info->compact_unwind_section = 0; - info->compact_unwind_section_length = 0; - - return true; - } - #endif -#endif - inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, UnwindInfoSections &info) { #ifdef __APPLE__ dyld_unwind_sections dyldInfo; if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) { info.dso_base = (uintptr_t)dyldInfo.mh; - #if _LIBUNWIND_SUPPORT_DWARF_UNWIND + #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section; info.dwarf_section_length = dyldInfo.dwarf_section_length; #endif @@ -362,23 +397,76 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length; return true; } -#elif _LIBUNWIND_ARM_EHABI - #ifdef _LIBUNWIND_IS_BAREMETAL +#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL) + // Bare metal is statically linked, so no need to ask the dynamic loader + info.dwarf_section_length = (uintptr_t)(&__eh_frame_end - &__eh_frame_start); + info.dwarf_section = (uintptr_t)(&__eh_frame_start); + _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p", + (void *)info.dwarf_section, (void *)info.dwarf_section_length); +#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) + info.dwarf_index_section = (uintptr_t)(&__eh_frame_hdr_start); + info.dwarf_index_section_length = (uintptr_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start); + _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p", + (void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length); +#endif + if (info.dwarf_section_length) + return true; +#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL) // Bare metal is statically linked, so no need to ask the dynamic loader info.arm_section = (uintptr_t)(&__exidx_start); info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start); - #else - int length = 0; - info.arm_section = (uintptr_t) dl_unwind_find_exidx( - (_Unwind_Ptr) targetAddr, &length); - info.arm_section_length = (uintptr_t)length; - #endif - _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %X length %x\n", - info.arm_section, info.arm_section_length); + _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p", + (void *)info.arm_section, (void *)info.arm_section_length); if (info.arm_section && info.arm_section_length) return true; -#elif _LIBUNWIND_SUPPORT_DWARF_UNWIND -#if _LIBUNWIND_SUPPORT_DWARF_INDEX +#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32) + HMODULE mods[1024]; + HANDLE process = GetCurrentProcess(); + DWORD needed; + + if (!EnumProcessModules(process, mods, sizeof(mods), &needed)) + return false; + + for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) { + PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i]; + PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew); + PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader; + PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh); + bool found_obj = false; + bool found_hdr = false; + + info.dso_base = (uintptr_t)mods[i]; + for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) { + uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i]; + uintptr_t end = begin + pish->Misc.VirtualSize; + if (!strncmp((const char *)pish->Name, ".text", + IMAGE_SIZEOF_SHORT_NAME)) { + if (targetAddr >= begin && targetAddr < end) + found_obj = true; + } else if (!strncmp((const char *)pish->Name, ".eh_frame", + IMAGE_SIZEOF_SHORT_NAME)) { + info.dwarf_section = begin; + info.dwarf_section_length = pish->Misc.VirtualSize; + found_hdr = true; + } + if (found_obj && found_hdr) + return true; + } + } + return false; +#elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32) + // Don't even bother, since Windows has functions that do all this stuff + // for us. + return true; +#elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__) && \ + (__ANDROID_API__ < 21) + int length = 0; + info.arm_section = + (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length); + info.arm_section_length = (uintptr_t)length; + if (info.arm_section && info.arm_section_length) + return true; +#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) struct dl_iterate_cb_data { LocalAddressSpace *addressSpace; UnwindInfoSections *sects; @@ -389,7 +477,6 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, int found = dl_iterate_phdr( [](struct dl_phdr_info *pinfo, size_t, void *data) -> int { auto cbdata = static_cast(data); - size_t object_length; bool found_obj = false; bool found_hdr = false; @@ -406,11 +493,32 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, #if !defined(Elf_Phdr) typedef ElfW(Phdr) Elf_Phdr; #endif +#if !defined(Elf_Addr) && defined(__ANDROID__) + typedef ElfW(Addr) Elf_Addr; +#endif + + #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + #if !defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) + #error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform." + #endif + size_t object_length; +#if defined(__ANDROID__) + Elf_Addr image_base = + pinfo->dlpi_phnum + ? reinterpret_cast(pinfo->dlpi_phdr) - + reinterpret_cast(pinfo->dlpi_phdr) + ->p_offset + : 0; +#endif for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) { const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i]; if (phdr->p_type == PT_LOAD) { uintptr_t begin = pinfo->dlpi_addr + phdr->p_vaddr; +#if defined(__ANDROID__) + if (pinfo->dlpi_addr == 0 && phdr->p_vaddr < image_base) + begin = begin + image_base; +#endif uintptr_t end = begin + phdr->p_memsz; if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) { cbdata->sects->dso_base = begin; @@ -420,6 +528,10 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, } else if (phdr->p_type == PT_GNU_EH_FRAME) { EHHeaderParser::EHHeaderInfo hdrInfo; uintptr_t eh_frame_hdr_start = pinfo->dlpi_addr + phdr->p_vaddr; +#if defined(__ANDROID__) + if (pinfo->dlpi_addr == 0 && phdr->p_vaddr < image_base) + eh_frame_hdr_start = eh_frame_hdr_start + image_base; +#endif cbdata->sects->dwarf_index_section = eh_frame_hdr_start; cbdata->sects->dwarf_index_section_length = phdr->p_memsz; EHHeaderParser::decodeEHHdr( @@ -436,12 +548,26 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, } else { return false; } + #else // defined(_LIBUNWIND_ARM_EHABI) + for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) { + const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i]; + if (phdr->p_type == PT_LOAD) { + uintptr_t begin = pinfo->dlpi_addr + phdr->p_vaddr; + uintptr_t end = begin + phdr->p_memsz; + if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) + found_obj = true; + } else if (phdr->p_type == PT_ARM_EXIDX) { + uintptr_t exidx_start = pinfo->dlpi_addr + phdr->p_vaddr; + cbdata->sects->arm_section = exidx_start; + cbdata->sects->arm_section_length = phdr->p_memsz; + found_hdr = true; + } + } + return found_obj && found_hdr; + #endif }, &cb_data); return static_cast(found); -#else -#error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform." -#endif #endif return false; @@ -462,7 +588,7 @@ inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) { inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf, size_t bufLen, unw_word_t *offset) { -#ifndef _LIBUNWIND_IS_BAREMETAL +#if _LIBUNWIND_USE_DLADDR Dl_info dyldInfo; if (dladdr((void *)addr, &dyldInfo)) { if (dyldInfo.dli_sname != NULL) { @@ -479,14 +605,14 @@ inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf, #ifdef UNW_REMOTE -/// OtherAddressSpace is used as a template parameter to UnwindCursor when +/// RemoteAddressSpace is used as a template parameter to UnwindCursor when /// unwinding a thread in the another process. The other process can be a /// different endianness and a different pointer size which is handled by /// the P template parameter. template -class OtherAddressSpace { +class RemoteAddressSpace { public: - OtherAddressSpace(task_t task) : fTask(task) {} + RemoteAddressSpace(task_t task) : fTask(task) {} typedef typename P::uint_t pint_t; @@ -495,6 +621,7 @@ class OtherAddressSpace { uint32_t get32(pint_t addr); uint64_t get64(pint_t addr); pint_t getP(pint_t addr); + uint64_t getRegister(pint_t addr); uint64_t getULEB128(pint_t &addr, pint_t end); int64_t getSLEB128(pint_t &addr, pint_t end); pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, @@ -509,27 +636,32 @@ class OtherAddressSpace { task_t fTask; }; -template uint8_t OtherAddressSpace

::get8(pint_t addr) { +template uint8_t RemoteAddressSpace

::get8(pint_t addr) { return *((uint8_t *)localCopy(addr)); } -template uint16_t OtherAddressSpace

::get16(pint_t addr) { +template uint16_t RemoteAddressSpace

::get16(pint_t addr) { return P::E::get16(*(uint16_t *)localCopy(addr)); } -template uint32_t OtherAddressSpace

::get32(pint_t addr) { +template uint32_t RemoteAddressSpace

::get32(pint_t addr) { return P::E::get32(*(uint32_t *)localCopy(addr)); } -template uint64_t OtherAddressSpace

::get64(pint_t addr) { +template uint64_t RemoteAddressSpace

::get64(pint_t addr) { return P::E::get64(*(uint64_t *)localCopy(addr)); } template -typename P::uint_t OtherAddressSpace

::getP(pint_t addr) { +typename P::uint_t RemoteAddressSpace

::getP(pint_t addr) { return P::getP(*(uint64_t *)localCopy(addr)); } +template +typename P::uint_t OtherAddressSpace

::getRegister(pint_t addr) { + return P::getRegister(*(uint64_t *)localCopy(addr)); +} + template uint64_t OtherAddressSpace

::getULEB128(pint_t &addr, pint_t end) { uintptr_t size = (end - addr); @@ -541,7 +673,7 @@ uint64_t OtherAddressSpace

::getULEB128(pint_t &addr, pint_t end) { } template -int64_t OtherAddressSpace

::getSLEB128(pint_t &addr, pint_t end) { +int64_t RemoteAddressSpace

::getSLEB128(pint_t &addr, pint_t end) { uintptr_t size = (end - addr); LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr); LocalAddressSpace::pint_t sladdr = laddr; @@ -550,13 +682,14 @@ int64_t OtherAddressSpace

::getSLEB128(pint_t &addr, pint_t end) { return result; } -template void *OtherAddressSpace

::localCopy(pint_t addr) { +template void *RemoteAddressSpace

::localCopy(pint_t addr) { // FIX ME } template -bool OtherAddressSpace

::findFunctionName(pint_t addr, char *buf, - size_t bufLen, unw_word_t *offset) { +bool RemoteAddressSpace

::findFunctionName(pint_t addr, char *buf, + size_t bufLen, + unw_word_t *offset) { // FIX ME } @@ -572,7 +705,7 @@ struct unw_addr_space { /// a 32-bit intel process. struct unw_addr_space_i386 : public unw_addr_space { unw_addr_space_i386(task_t task) : oas(task) {} - OtherAddressSpace > oas; + RemoteAddressSpace> oas; }; /// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t @@ -580,7 +713,7 @@ struct unw_addr_space_i386 : public unw_addr_space { /// a 64-bit intel process. struct unw_addr_space_x86_64 : public unw_addr_space { unw_addr_space_x86_64(task_t task) : oas(task) {} - OtherAddressSpace > oas; + RemoteAddressSpace> oas; }; /// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points @@ -588,7 +721,14 @@ struct unw_addr_space_x86_64 : public unw_addr_space { /// a 32-bit PowerPC process. struct unw_addr_space_ppc : public unw_addr_space { unw_addr_space_ppc(task_t task) : oas(task) {} - OtherAddressSpace > oas; + RemoteAddressSpace> oas; +}; + +/// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points +/// to when examining a 64-bit PowerPC process. +struct unw_addr_space_ppc64 : public unw_addr_space { + unw_addr_space_ppc64(task_t task) : oas(task) {} + RemoteAddressSpace> oas; }; #endif // UNW_REMOTE diff --git a/src/CompactUnwinder.hpp b/src/CompactUnwinder.hpp index f528fba984d..7b97bf84ceb 100644 --- a/src/CompactUnwinder.hpp +++ b/src/CompactUnwinder.hpp @@ -19,7 +19,6 @@ #include #include -#include "AddressSpace.hpp" #include "Registers.hpp" #define EXTRACT_BITS(value, mask) \ @@ -105,7 +104,7 @@ int CompactUnwinder_x86::stepWithCompactEncodingEBPFrame( default: (void)functionStart; _LIBUNWIND_DEBUG_LOG("bad register for EBP frame, encoding=%08X for " - "function starting at 0x%X\n", + "function starting at 0x%X", compactEncoding, functionStart); _LIBUNWIND_ABORT("invalid compact unwind encoding"); } @@ -224,7 +223,7 @@ int CompactUnwinder_x86::stepWithCompactEncodingFrameless( break; default: _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for " - "function starting at 0x%X\n", + "function starting at 0x%X", encoding, functionStart); _LIBUNWIND_ABORT("invalid compact unwind encoding"); } @@ -336,7 +335,7 @@ int CompactUnwinder_x86_64::stepWithCompactEncodingRBPFrame( default: (void)functionStart; _LIBUNWIND_DEBUG_LOG("bad register for RBP frame, encoding=%08X for " - "function starting at 0x%llX\n", + "function starting at 0x%llX", compactEncoding, functionStart); _LIBUNWIND_ABORT("invalid compact unwind encoding"); } @@ -455,7 +454,7 @@ int CompactUnwinder_x86_64::stepWithCompactEncodingFrameless( break; default: _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for " - "function starting at 0x%llX\n", + "function starting at 0x%llX", encoding, functionStart); _LIBUNWIND_ABORT("invalid compact unwind encoding"); } diff --git a/src/DwarfInstructions.hpp b/src/DwarfInstructions.hpp index ce90aa05f53..ec70c0a11f7 100644 --- a/src/DwarfInstructions.hpp +++ b/src/DwarfInstructions.hpp @@ -6,7 +6,7 @@ // Source Licenses. See LICENSE.TXT for details. // // -// Processor specific interpretation of dwarf unwind info. +// Processor specific interpretation of DWARF unwind info. // //===----------------------------------------------------------------------===// @@ -18,7 +18,6 @@ #include #include "dwarf2.h" -#include "AddressSpace.hpp" #include "Registers.hpp" #include "DwarfParser.hpp" #include "config.h" @@ -27,7 +26,7 @@ namespace libunwind { -/// DwarfInstructions maps abtract dwarf unwind instructions to a particular +/// DwarfInstructions maps abtract DWARF unwind instructions to a particular /// architecture template class DwarfInstructions { @@ -83,10 +82,10 @@ typename A::pint_t DwarfInstructions::getSavedRegister( const RegisterLocation &savedReg) { switch (savedReg.location) { case CFI_Parser::kRegisterInCFA: - return addressSpace.getP(cfa + (pint_t)savedReg.value); + return addressSpace.getRegister(cfa + (pint_t)savedReg.value); case CFI_Parser::kRegisterAtExpression: - return addressSpace.getP( + return addressSpace.getRegister( evaluateExpression((pint_t)savedReg.value, addressSpace, registers, cfa)); @@ -160,15 +159,15 @@ int DwarfInstructions::stepWithDwarf(A &addressSpace, pint_t pc, &cieInfo) == NULL) { PrologInfo prolog; if (CFI_Parser::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc, - &prolog)) { + R::getArch(), &prolog)) { // get pointer to cfa (architecture specific) pint_t cfa = getCFA(addressSpace, prolog, registers); - // restore registers that dwarf says were saved + // restore registers that DWARF says were saved R newRegisters = registers; pint_t returnAddress = 0; const int lastReg = R::lastDwarfRegNum(); - assert((int)CFI_Parser::kMaxRegisterNumber > lastReg && + assert(static_cast(CFI_Parser::kMaxRegisterNumber) >= lastReg && "register range too large"); assert(lastReg >= (int)cieInfo.returnAddressRegister && "register range does not contain return address register"); @@ -199,6 +198,42 @@ int DwarfInstructions::stepWithDwarf(A &addressSpace, pint_t pc, // restoring SP means setting it to CFA. newRegisters.setSP(cfa); +#if defined(_LIBUNWIND_TARGET_AARCH64) + // If the target is aarch64 then the return address may have been signed + // using the v8.3 pointer authentication extensions. The original + // return address needs to be authenticated before the return address is + // restored. autia1716 is used instead of autia as autia1716 assembles + // to a NOP on pre-v8.3a architectures. + if ((R::getArch() == REGISTERS_ARM64) && + prolog.savedRegisters[UNW_ARM64_RA_SIGN_STATE].value) { +#if !defined(_LIBUNWIND_IS_NATIVE_ONLY) + return UNW_ECROSSRASIGNING; +#else + register unsigned long long x17 __asm("x17") = returnAddress; + register unsigned long long x16 __asm("x16") = cfa; + + // These are the autia1716/autib1716 instructions. The hint instructions + // are used here as gcc does not assemble autia1716/autib1716 for pre + // armv8.3a targets. + if (cieInfo.addressesSignedWithBKey) + asm("hint 0xe" : "+r"(x17) : "r"(x16)); // autib1716 + else + asm("hint 0xc" : "+r"(x17) : "r"(x16)); // autia1716 + returnAddress = x17; +#endif + } +#endif + +#if defined(_LIBUNWIND_TARGET_SPARC) + if (R::getArch() == REGISTERS_SPARC) { + // Skip call site instruction and delay slot + returnAddress += 8; + // Skip unimp instruction if function returns a struct + if ((addressSpace.get32(returnAddress) & 0xC1C00000) == 0) + returnAddress += 4; + } +#endif + // Return address is address after call site instruction, so setting IP to // that does simualates a return. newRegisters.setIP(returnAddress); @@ -480,7 +515,7 @@ DwarfInstructions::evaluateExpression(pint_t expression, A &addressSpace, case DW_OP_plus_uconst: // pop stack, add uelb128 constant, push result - *sp += addressSpace.getULEB128(p, expressionEnd); + *sp += static_cast(addressSpace.getULEB128(p, expressionEnd)); if (log) fprintf(stderr, "add constant\n"); break; @@ -744,7 +779,7 @@ DwarfInstructions::evaluateExpression(pint_t expression, A &addressSpace, case DW_OP_call4: case DW_OP_call_ref: default: - _LIBUNWIND_ABORT("dwarf opcode not implemented"); + _LIBUNWIND_ABORT("DWARF opcode not implemented"); } } diff --git a/src/DwarfParser.hpp b/src/DwarfParser.hpp index a19f0510a37..a2c6d7f8db9 100644 --- a/src/DwarfParser.hpp +++ b/src/DwarfParser.hpp @@ -20,13 +20,14 @@ #include "libunwind.h" #include "dwarf2.h" +#include "Registers.hpp" -#include "AddressSpace.hpp" +#include "config.h" namespace libunwind { /// CFI_Parser does basic parsing of a CFI (Call Frame Information) records. -/// See Dwarf Spec for details: +/// See DWARF Spec for details: /// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html /// template @@ -49,6 +50,9 @@ class CFI_Parser { bool isSignalFrame; bool fdesHaveAugmentationData; uint8_t returnAddressRegister; +#if defined(_LIBUNWIND_TARGET_AARCH64) + bool addressesSignedWithBKey; +#endif }; /// Information about an FDE (Frame Description Entry) @@ -62,7 +66,7 @@ class CFI_Parser { }; enum { - kMaxRegisterNumber = 120 + kMaxRegisterNumber = _LIBUNWIND_HIGHEST_DWARF_REGISTER }; enum RegisterSavedWhere { kRegisterUnused, @@ -77,7 +81,7 @@ class CFI_Parser { int64_t value; }; /// Information about a frame layout and registers saved determined - /// by "running" the dwarf FDE "instructions" + /// by "running" the DWARF FDE "instructions" struct PrologInfo { uint32_t cfaRegister; int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset @@ -86,7 +90,7 @@ class CFI_Parser { uint32_t codeOffsetAtStackDecrement; bool registersInOtherRegisters; bool sameValueUsed; - RegisterLocation savedRegisters[kMaxRegisterNumber]; + RegisterLocation savedRegisters[kMaxRegisterNumber + 1]; }; struct PrologInfoStackEntry { @@ -103,7 +107,7 @@ class CFI_Parser { FDE_Info *fdeInfo, CIE_Info *cieInfo); static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo, const CIE_Info &cieInfo, pint_t upToPC, - PrologInfo *results); + int arch, PrologInfo *results); static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo); @@ -111,7 +115,7 @@ class CFI_Parser { static bool parseInstructions(A &addressSpace, pint_t instructions, pint_t instructionsEnd, const CIE_Info &cieInfo, pint_t pcoffset, - PrologInfoStackEntry *&rememberStack, + PrologInfoStackEntry *&rememberStack, int arch, PrologInfo *results); }; @@ -138,23 +142,23 @@ const char *CFI_Parser::decodeFDE(A &addressSpace, pint_t fdeStart, if (err != NULL) return err; p += 4; - // parse pc begin and range + // Parse pc begin and range. pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding); pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F); - // parse rest of info + // Parse rest of info. fdeInfo->lsda = 0; - // check for augmentation length + // Check for augmentation length. if (cieInfo->fdesHaveAugmentationData) { pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI); pint_t endOfAug = p + augLen; if (cieInfo->lsdaEncoding != DW_EH_PE_omit) { - // peek at value (without indirection). Zero means no lsda + // Peek at value (without indirection). Zero means no LSDA. pint_t lsdaStart = p; if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) { - // reset pointer and re-parse lsda address + // Reset pointer and re-parse LSDA address. p = lsdaStart; fdeInfo->lsda = addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); @@ -192,23 +196,23 @@ bool CFI_Parser::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, return false; // end marker uint32_t id = addressSpace.get32(p); if (id == 0) { - // skip over CIEs + // Skip over CIEs. p += cfiLength; } else { - // process FDE to see if it covers pc + // Process FDE to see if it covers pc. pint_t nextCFI = p + cfiLength; uint32_t ciePointer = addressSpace.get32(p); pint_t cieStart = p - ciePointer; - // validate pointer to CIE is within section + // Validate pointer to CIE is within section. if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) { if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) { p += 4; - // parse pc begin and range + // Parse pc begin and range. pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding); pint_t pcRange = addressSpace.getEncodedP( p, nextCFI, cieInfo->pointerEncoding & 0x0F); - // test if pc is within the function this FDE covers + // Test if pc is within the function this FDE covers. if ((pcStart < pc) && (pc <= pcStart + pcRange)) { // parse rest of info fdeInfo->lsda = 0; @@ -217,11 +221,11 @@ bool CFI_Parser::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI); pint_t endOfAug = p + augLen; if (cieInfo->lsdaEncoding != DW_EH_PE_omit) { - // peek at value (without indirection). Zero means no lsda + // Peek at value (without indirection). Zero means no LSDA. pint_t lsdaStart = p; if (addressSpace.getEncodedP( p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) { - // reset pointer and re-parse lsda address + // Reset pointer and re-parse LSDA address. p = lsdaStart; fdeInfo->lsda = addressSpace .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); @@ -239,7 +243,7 @@ bool CFI_Parser::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, // pc is not in begin/range, skip this FDE } } else { - // malformed CIE, now augmentation describing pc range encoding + // Malformed CIE, now augmentation describing pc range encoding. } } else { // malformed FDE. CIE is bad @@ -263,6 +267,9 @@ const char *CFI_Parser::parseCIE(A &addressSpace, pint_t cie, cieInfo->dataAlignFactor = 0; cieInfo->isSignalFrame = false; cieInfo->fdesHaveAugmentationData = false; +#if defined(_LIBUNWIND_TARGET_AARCH64) + cieInfo->addressesSignedWithBKey = false; +#endif cieInfo->cieStart = cie; pint_t p = cie; pint_t cieLength = (pint_t)addressSpace.get32(p); @@ -326,6 +333,11 @@ const char *CFI_Parser::parseCIE(A &addressSpace, pint_t cie, case 'S': cieInfo->isSignalFrame = true; break; +#if defined(_LIBUNWIND_TARGET_AARCH64) + case 'B': + cieInfo->addressesSignedWithBKey = true; + break; +#endif default: // ignore unknown letters break; @@ -338,12 +350,12 @@ const char *CFI_Parser::parseCIE(A &addressSpace, pint_t cie, } -/// "run" the dwarf instructions and create the abstact PrologInfo for an FDE +/// "run" the DWARF instructions and create the abstact PrologInfo for an FDE template bool CFI_Parser::parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo, const CIE_Info &cieInfo, pint_t upToPC, - PrologInfo *results) { + int arch, PrologInfo *results) { // clear results memset(results, '\0', sizeof(PrologInfo)); PrologInfoStackEntry *rememberStack = NULL; @@ -351,28 +363,28 @@ bool CFI_Parser::parseFDEInstructions(A &addressSpace, // parse CIE then FDE instructions return parseInstructions(addressSpace, cieInfo.cieInstructions, cieInfo.cieStart + cieInfo.cieLength, cieInfo, - (pint_t)(-1), rememberStack, results) && + (pint_t)(-1), rememberStack, arch, results) && parseInstructions(addressSpace, fdeInfo.fdeInstructions, fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo, - upToPC - fdeInfo.pcStart, rememberStack, results); + upToPC - fdeInfo.pcStart, rememberStack, arch, + results); } -/// "run" the dwarf instructions +/// "run" the DWARF instructions template bool CFI_Parser::parseInstructions(A &addressSpace, pint_t instructions, pint_t instructionsEnd, const CIE_Info &cieInfo, pint_t pcoffset, PrologInfoStackEntry *&rememberStack, - PrologInfo *results) { - const bool logDwarf = false; + int arch, PrologInfo *results) { pint_t p = instructions; pint_t codeOffset = 0; PrologInfo initialState = *results; - if (logDwarf) - fprintf(stderr, "parseInstructions(instructions=0x%0" PRIx64 ")\n", - (uint64_t)instructionsEnd); - // see Dwarf Spec, section 6.4.2 for details on unwind opcodes + _LIBUNWIND_TRACE_DWARF("parseInstructions(instructions=0x%0" PRIx64 ")\n", + static_cast(instructionsEnd)); + + // see DWARF Spec, section 6.4.2 for details on unwind opcodes while ((p < instructionsEnd) && (codeOffset < pcoffset)) { uint64_t reg; uint64_t reg2; @@ -386,81 +398,71 @@ bool CFI_Parser::parseInstructions(A &addressSpace, pint_t instructions, ++p; switch (opcode) { case DW_CFA_nop: - if (logDwarf) - fprintf(stderr, "DW_CFA_nop\n"); + _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n"); break; case DW_CFA_set_loc: codeOffset = addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding); - if (logDwarf) - fprintf(stderr, "DW_CFA_set_loc\n"); + _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n"); break; case DW_CFA_advance_loc1: codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor); p += 1; - if (logDwarf) - fprintf(stderr, "DW_CFA_advance_loc1: new offset=%" PRIu64 "\n", - (uint64_t)codeOffset); + _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n", + static_cast(codeOffset)); break; case DW_CFA_advance_loc2: codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor); p += 2; - if (logDwarf) - fprintf(stderr, "DW_CFA_advance_loc2: new offset=%" PRIu64 "\n", - (uint64_t)codeOffset); + _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n", + static_cast(codeOffset)); break; case DW_CFA_advance_loc4: codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor); p += 4; - if (logDwarf) - fprintf(stderr, "DW_CFA_advance_loc4: new offset=%" PRIu64 "\n", - (uint64_t)codeOffset); + _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n", + static_cast(codeOffset)); break; case DW_CFA_offset_extended: reg = addressSpace.getULEB128(p, instructionsEnd); offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; if (reg > kMaxRegisterNumber) { - fprintf(stderr, - "malformed DW_CFA_offset_extended dwarf unwind, reg too big\n"); + _LIBUNWIND_LOG0( + "malformed DW_CFA_offset_extended DWARF unwind, reg too big"); return false; } results->savedRegisters[reg].location = kRegisterInCFA; results->savedRegisters[reg].value = offset; - if (logDwarf) - fprintf(stderr, - "DW_CFA_offset_extended(reg=%" PRIu64 ", offset=%" PRId64 ")\n", - reg, offset); + _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", " + "offset=%" PRId64 ")\n", + reg, offset); break; case DW_CFA_restore_extended: reg = addressSpace.getULEB128(p, instructionsEnd); - ; if (reg > kMaxRegisterNumber) { - fprintf( - stderr, - "malformed DW_CFA_restore_extended dwarf unwind, reg too big\n"); + _LIBUNWIND_LOG0( + "malformed DW_CFA_restore_extended DWARF unwind, reg too big"); return false; } results->savedRegisters[reg] = initialState.savedRegisters[reg]; - if (logDwarf) - fprintf(stderr, "DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg); + _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg); break; case DW_CFA_undefined: reg = addressSpace.getULEB128(p, instructionsEnd); if (reg > kMaxRegisterNumber) { - fprintf(stderr, - "malformed DW_CFA_undefined dwarf unwind, reg too big\n"); + _LIBUNWIND_LOG0( + "malformed DW_CFA_undefined DWARF unwind, reg too big"); return false; } results->savedRegisters[reg].location = kRegisterUnused; - if (logDwarf) - fprintf(stderr, "DW_CFA_undefined(reg=%" PRIu64 ")\n", reg); + _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg); break; case DW_CFA_same_value: reg = addressSpace.getULEB128(p, instructionsEnd); if (reg > kMaxRegisterNumber) { - fprintf(stderr, - "malformed DW_CFA_same_value dwarf unwind, reg too big\n"); + _LIBUNWIND_LOG0( + "malformed DW_CFA_same_value DWARF unwind, reg too big"); return false; } // DW_CFA_same_value unsupported @@ -470,29 +472,27 @@ bool CFI_Parser::parseInstructions(A &addressSpace, pint_t instructions, results->savedRegisters[reg].location = kRegisterUnused; // set flag to disable conversion to compact unwind results->sameValueUsed = true; - if (logDwarf) - fprintf(stderr, "DW_CFA_same_value(reg=%" PRIu64 ")\n", reg); + _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg); break; case DW_CFA_register: reg = addressSpace.getULEB128(p, instructionsEnd); reg2 = addressSpace.getULEB128(p, instructionsEnd); if (reg > kMaxRegisterNumber) { - fprintf(stderr, - "malformed DW_CFA_register dwarf unwind, reg too big\n"); + _LIBUNWIND_LOG0( + "malformed DW_CFA_register DWARF unwind, reg too big"); return false; } if (reg2 > kMaxRegisterNumber) { - fprintf(stderr, - "malformed DW_CFA_register dwarf unwind, reg2 too big\n"); + _LIBUNWIND_LOG0( + "malformed DW_CFA_register DWARF unwind, reg2 too big"); return false; } results->savedRegisters[reg].location = kRegisterInRegister; results->savedRegisters[reg].value = (int64_t)reg2; // set flag to disable conversion to compact unwind results->registersInOtherRegisters = true; - if (logDwarf) - fprintf(stderr, "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", - reg, reg2); + _LIBUNWIND_TRACE_DWARF( + "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2); break; #if !defined(_LIBUNWIND_NO_HEAP) case DW_CFA_remember_state: @@ -505,8 +505,7 @@ bool CFI_Parser::parseInstructions(A &addressSpace, pint_t instructions, } else { return false; } - if (logDwarf) - fprintf(stderr, "DW_CFA_remember_state\n"); + _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n"); break; case DW_CFA_restore_state: if (rememberStack != NULL) { @@ -517,202 +516,243 @@ bool CFI_Parser::parseInstructions(A &addressSpace, pint_t instructions, } else { return false; } - if (logDwarf) - fprintf(stderr, "DW_CFA_restore_state\n"); + _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n"); break; #endif case DW_CFA_def_cfa: reg = addressSpace.getULEB128(p, instructionsEnd); offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd); if (reg > kMaxRegisterNumber) { - fprintf(stderr, "malformed DW_CFA_def_cfa dwarf unwind, reg too big\n"); + _LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big"); return false; } results->cfaRegister = (uint32_t)reg; results->cfaRegisterOffset = (int32_t)offset; - if (logDwarf) - fprintf(stderr, "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", - reg, offset); + _LIBUNWIND_TRACE_DWARF( + "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", reg, offset); break; case DW_CFA_def_cfa_register: reg = addressSpace.getULEB128(p, instructionsEnd); if (reg > kMaxRegisterNumber) { - fprintf( - stderr, - "malformed DW_CFA_def_cfa_register dwarf unwind, reg too big\n"); + _LIBUNWIND_LOG0( + "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big"); return false; } results->cfaRegister = (uint32_t)reg; - if (logDwarf) - fprintf(stderr, "DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg); + _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg); break; case DW_CFA_def_cfa_offset: results->cfaRegisterOffset = (int32_t) addressSpace.getULEB128(p, instructionsEnd); results->codeOffsetAtStackDecrement = (uint32_t)codeOffset; - if (logDwarf) - fprintf(stderr, "DW_CFA_def_cfa_offset(%d)\n", - results->cfaRegisterOffset); + _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n", + results->cfaRegisterOffset); break; case DW_CFA_def_cfa_expression: results->cfaRegister = 0; results->cfaExpression = (int64_t)p; length = addressSpace.getULEB128(p, instructionsEnd); - p += length; - if (logDwarf) - fprintf(stderr, "DW_CFA_def_cfa_expression(expression=0x%" PRIx64 - ", length=%" PRIu64 ")\n", - results->cfaExpression, length); + assert(length < static_cast(~0) && "pointer overflow"); + p += static_cast(length); + _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64 + ", length=%" PRIu64 ")\n", + results->cfaExpression, length); break; case DW_CFA_expression: reg = addressSpace.getULEB128(p, instructionsEnd); if (reg > kMaxRegisterNumber) { - fprintf(stderr, - "malformed DW_CFA_expression dwarf unwind, reg too big\n"); + _LIBUNWIND_LOG0( + "malformed DW_CFA_expression DWARF unwind, reg too big"); return false; } results->savedRegisters[reg].location = kRegisterAtExpression; results->savedRegisters[reg].value = (int64_t)p; length = addressSpace.getULEB128(p, instructionsEnd); - p += length; - if (logDwarf) - fprintf(stderr, "DW_CFA_expression(reg=%" PRIu64 - ", expression=0x%" PRIx64 ", length=%" PRIu64 ")\n", - reg, results->savedRegisters[reg].value, length); + assert(length < static_cast(~0) && "pointer overflow"); + p += static_cast(length); + _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", " + "expression=0x%" PRIx64 ", " + "length=%" PRIu64 ")\n", + reg, results->savedRegisters[reg].value, length); break; case DW_CFA_offset_extended_sf: reg = addressSpace.getULEB128(p, instructionsEnd); if (reg > kMaxRegisterNumber) { - fprintf( - stderr, - "malformed DW_CFA_offset_extended_sf dwarf unwind, reg too big\n"); + _LIBUNWIND_LOG0( + "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big"); return false; } offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; results->savedRegisters[reg].location = kRegisterInCFA; results->savedRegisters[reg].value = offset; - if (logDwarf) - fprintf(stderr, "DW_CFA_offset_extended_sf(reg=%" PRIu64 - ", offset=%" PRId64 ")\n", - reg, offset); + _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", " + "offset=%" PRId64 ")\n", + reg, offset); break; case DW_CFA_def_cfa_sf: reg = addressSpace.getULEB128(p, instructionsEnd); offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; if (reg > kMaxRegisterNumber) { - fprintf(stderr, - "malformed DW_CFA_def_cfa_sf dwarf unwind, reg too big\n"); + _LIBUNWIND_LOG0( + "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big"); return false; } results->cfaRegister = (uint32_t)reg; results->cfaRegisterOffset = (int32_t)offset; - if (logDwarf) - fprintf(stderr, - "DW_CFA_def_cfa_sf(reg=%" PRIu64 ", offset=%" PRId64 ")\n", reg, - offset); + _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", " + "offset=%" PRId64 ")\n", + reg, offset); break; case DW_CFA_def_cfa_offset_sf: results->cfaRegisterOffset = (int32_t) (addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor); results->codeOffsetAtStackDecrement = (uint32_t)codeOffset; - if (logDwarf) - fprintf(stderr, "DW_CFA_def_cfa_offset_sf(%d)\n", - results->cfaRegisterOffset); + _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n", + results->cfaRegisterOffset); break; case DW_CFA_val_offset: reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG( + "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64 + ") out of range\n", + reg); + return false; + } offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; results->savedRegisters[reg].location = kRegisterOffsetFromCFA; results->savedRegisters[reg].value = offset; - if (logDwarf) - fprintf(stderr, - "DW_CFA_val_offset(reg=%" PRIu64 ", offset=%" PRId64 "\n", reg, - offset); + _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", " + "offset=%" PRId64 "\n", + reg, offset); break; case DW_CFA_val_offset_sf: reg = addressSpace.getULEB128(p, instructionsEnd); if (reg > kMaxRegisterNumber) { - fprintf(stderr, - "malformed DW_CFA_val_offset_sf dwarf unwind, reg too big\n"); + _LIBUNWIND_LOG0( + "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big"); return false; } offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; results->savedRegisters[reg].location = kRegisterOffsetFromCFA; results->savedRegisters[reg].value = offset; - if (logDwarf) - fprintf(stderr, - "DW_CFA_val_offset_sf(reg=%" PRIu64 ", offset=%" PRId64 "\n", - reg, offset); + _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", " + "offset=%" PRId64 "\n", + reg, offset); break; case DW_CFA_val_expression: reg = addressSpace.getULEB128(p, instructionsEnd); if (reg > kMaxRegisterNumber) { - fprintf(stderr, - "malformed DW_CFA_val_expression dwarf unwind, reg too big\n"); + _LIBUNWIND_LOG0( + "malformed DW_CFA_val_expression DWARF unwind, reg too big"); return false; } results->savedRegisters[reg].location = kRegisterIsExpression; results->savedRegisters[reg].value = (int64_t)p; length = addressSpace.getULEB128(p, instructionsEnd); - p += length; - if (logDwarf) - fprintf(stderr, "DW_CFA_val_expression(reg=%" PRIu64 - ", expression=0x%" PRIx64 ", length=%" PRIu64 ")\n", - reg, results->savedRegisters[reg].value, length); + assert(length < static_cast(~0) && "pointer overflow"); + p += static_cast(length); + _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", " + "expression=0x%" PRIx64 ", length=%" PRIu64 ")\n", + reg, results->savedRegisters[reg].value, length); break; case DW_CFA_GNU_args_size: length = addressSpace.getULEB128(p, instructionsEnd); results->spExtraArgSize = (uint32_t)length; - if (logDwarf) - fprintf(stderr, "DW_CFA_GNU_args_size(%" PRIu64 ")\n", length); + _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length); break; case DW_CFA_GNU_negative_offset_extended: reg = addressSpace.getULEB128(p, instructionsEnd); if (reg > kMaxRegisterNumber) { - fprintf(stderr, "malformed DW_CFA_GNU_negative_offset_extended dwarf " - "unwind, reg too big\n"); + _LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF " + "unwind, reg too big"); return false; } offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; results->savedRegisters[reg].location = kRegisterInCFA; results->savedRegisters[reg].value = -offset; - if (logDwarf) - fprintf(stderr, "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", - offset); + _LIBUNWIND_TRACE_DWARF( + "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset); break; + +#if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC) + // The same constant is used to represent different instructions on + // AArch64 (negate_ra_state) and SPARC (window_save). + static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save, + "uses the same constant"); + case DW_CFA_AARCH64_negate_ra_state: + switch (arch) { +#if defined(_LIBUNWIND_TARGET_AARCH64) + case REGISTERS_ARM64: + results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^= 0x1; + _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n"); + break; +#endif +#if defined(_LIBUNWIND_TARGET_SPARC) + // case DW_CFA_GNU_window_save: + case REGISTERS_SPARC: + _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n"); + for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) { + results->savedRegisters[reg].location = kRegisterInRegister; + results->savedRegisters[reg].value = + ((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0; + } + + for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) { + results->savedRegisters[reg].location = kRegisterInCFA; + results->savedRegisters[reg].value = + ((int64_t)reg - UNW_SPARC_L0) * 4; + } + break; +#endif + } + break; +#else + (void)arch; +#endif + default: operand = opcode & 0x3F; switch (opcode & 0xC0) { case DW_CFA_offset: reg = operand; + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64 + ") out of range", + reg); + return false; + } offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; results->savedRegisters[reg].location = kRegisterInCFA; results->savedRegisters[reg].value = offset; - if (logDwarf) - fprintf(stderr, "DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n", - operand, offset); + _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n", + operand, offset); break; case DW_CFA_advance_loc: codeOffset += operand * cieInfo.codeAlignFactor; - if (logDwarf) - fprintf(stderr, "DW_CFA_advance_loc: new offset=%" PRIu64 "\n", - (uint64_t)codeOffset); + _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n", + static_cast(codeOffset)); break; case DW_CFA_restore: reg = operand; + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG("malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64 + ") out of range", + reg); + return false; + } results->savedRegisters[reg] = initialState.savedRegisters[reg]; - if (logDwarf) - fprintf(stderr, "DW_CFA_restore(reg=%" PRIu64 ")\n", reg); + _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n", + static_cast(operand)); break; default: - if (logDwarf) - fprintf(stderr, "unknown CFA opcode 0x%02X\n", opcode); + _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode); return false; } } diff --git a/src/EHHeaderParser.hpp b/src/EHHeaderParser.hpp index 7945c7ba2fb..9bdaf5505ff 100644 --- a/src/EHHeaderParser.hpp +++ b/src/EHHeaderParser.hpp @@ -15,7 +15,6 @@ #include "libunwind.h" -#include "AddressSpace.hpp" #include "DwarfParser.hpp" namespace libunwind { @@ -68,7 +67,9 @@ void EHHeaderParser::decodeEHHdr(A &addressSpace, pint_t ehHdrStart, ehHdrInfo.eh_frame_ptr = addressSpace.getEncodedP(p, ehHdrEnd, eh_frame_ptr_enc, ehHdrStart); ehHdrInfo.fde_count = - addressSpace.getEncodedP(p, ehHdrEnd, fde_count_enc, ehHdrStart); + fde_count_enc == DW_EH_PE_omit + ? 0 + : addressSpace.getEncodedP(p, ehHdrEnd, fde_count_enc, ehHdrStart); ehHdrInfo.table = p; } @@ -85,7 +86,7 @@ bool EHHeaderParser::decodeTableEntry( const char *message = CFI_Parser::decodeFDE(addressSpace, fde, fdeInfo, cieInfo); if (message != NULL) { - _LIBUNWIND_DEBUG_LOG("EHHeaderParser::decodeTableEntry: bad fde: %s\n", + _LIBUNWIND_DEBUG_LOG("EHHeaderParser::decodeTableEntry: bad fde: %s", message); return false; } diff --git a/src/RWMutex.hpp b/src/RWMutex.hpp new file mode 100644 index 00000000000..50a78a57b08 --- /dev/null +++ b/src/RWMutex.hpp @@ -0,0 +1,77 @@ +//===----------------------------- Registers.hpp --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// +// Abstract interface to shared reader/writer log, hiding platform and +// configuration differences. +// +//===----------------------------------------------------------------------===// + +#ifndef __RWMUTEX_HPP__ +#define __RWMUTEX_HPP__ + +#if defined(_WIN32) +#include +#elif !defined(_LIBUNWIND_HAS_NO_THREADS) +#include +#endif + +namespace libunwind { + +#if defined(_LIBUNWIND_HAS_NO_THREADS) + +class _LIBUNWIND_HIDDEN RWMutex { +public: + bool lock_shared() { return true; } + bool unlock_shared() { return true; } + bool lock() { return true; } + bool unlock() { return true; } +}; + +#elif defined(_WIN32) + +class _LIBUNWIND_HIDDEN RWMutex { +public: + bool lock_shared() { + AcquireSRWLockShared(&_lock); + return true; + } + bool unlock_shared() { + ReleaseSRWLockShared(&_lock); + return true; + } + bool lock() { + AcquireSRWLockExclusive(&_lock); + return true; + } + bool unlock() { + ReleaseSRWLockExclusive(&_lock); + return true; + } + +private: + SRWLOCK _lock = SRWLOCK_INIT; +}; + +#else + +class _LIBUNWIND_HIDDEN RWMutex { +public: + bool lock_shared() { return pthread_rwlock_rdlock(&_lock) == 0; } + bool unlock_shared() { return pthread_rwlock_unlock(&_lock) == 0; } + bool lock() { return pthread_rwlock_wrlock(&_lock) == 0; } + bool unlock() { return pthread_rwlock_unlock(&_lock) == 0; } + +private: + pthread_rwlock_t _lock = PTHREAD_RWLOCK_INITIALIZER; +}; + +#endif + +} // namespace libunwind + +#endif // __RWMUTEX_HPP__ diff --git a/src/Registers.hpp b/src/Registers.hpp index ab874284000..a4f5a85f2a7 100644 --- a/src/Registers.hpp +++ b/src/Registers.hpp @@ -24,6 +24,18 @@ namespace libunwind { // For emulating 128-bit registers struct v128 { uint32_t vec[4]; }; +enum { + REGISTERS_X86, + REGISTERS_X86_64, + REGISTERS_PPC, + REGISTERS_PPC64, + REGISTERS_ARM64, + REGISTERS_ARM, + REGISTERS_OR1K, + REGISTERS_MIPS_O32, + REGISTERS_MIPS_NEWABI, + REGISTERS_SPARC, +}; #if defined(_LIBUNWIND_TARGET_I386) /// Registers_x86 holds the register state of a thread in a 32-bit intel @@ -42,9 +54,10 @@ class _LIBUNWIND_HIDDEN Registers_x86 { bool validVectorRegister(int) const { return false; } v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); - const char *getRegisterName(int num); + static const char *getRegisterName(int num); void jumpto(); - static int lastDwarfRegNum() { return 8; } + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86; } + static int getArch() { return REGISTERS_X86; } uint32_t getSP() const { return _registers.__esp; } void setSP(uint32_t value) { _registers.__esp = value; } @@ -122,9 +135,17 @@ inline uint32_t Registers_x86::getRegister(int regNum) const { return _registers.__edx; case UNW_X86_EBX: return _registers.__ebx; - case UNW_X86_EBP: - return _registers.__ebp; +#if !defined(__APPLE__) case UNW_X86_ESP: +#else + case UNW_X86_EBP: +#endif + return _registers.__ebp; +#if !defined(__APPLE__) + case UNW_X86_EBP: +#else + case UNW_X86_ESP: +#endif return _registers.__esp; case UNW_X86_ESI: return _registers.__esi; @@ -154,10 +175,18 @@ inline void Registers_x86::setRegister(int regNum, uint32_t value) { case UNW_X86_EBX: _registers.__ebx = value; return; +#if !defined(__APPLE__) + case UNW_X86_ESP: +#else case UNW_X86_EBP: +#endif _registers.__ebp = value; return; +#if !defined(__APPLE__) + case UNW_X86_EBP: +#else case UNW_X86_ESP: +#endif _registers.__esp = value; return; case UNW_X86_ESI: @@ -229,12 +258,13 @@ class _LIBUNWIND_HIDDEN Registers_x86_64 { bool validFloatRegister(int) const { return false; } double getFloatRegister(int num) const; void setFloatRegister(int num, double value); - bool validVectorRegister(int) const { return false; } + bool validVectorRegister(int) const; v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); - const char *getRegisterName(int num); + static const char *getRegisterName(int num); void jumpto(); - static int lastDwarfRegNum() { return 16; } + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64; } + static int getArch() { return REGISTERS_X86_64; } uint64_t getSP() const { return _registers.__rsp; } void setSP(uint64_t value) { _registers.__rsp = value; } @@ -276,8 +306,14 @@ class _LIBUNWIND_HIDDEN Registers_x86_64 { uint64_t __cs; uint64_t __fs; uint64_t __gs; +#if defined(_WIN64) + uint64_t __padding; // 16-byte align +#endif }; GPRs _registers; +#if defined(_WIN64) + v128 _xmm[16]; +#endif }; inline Registers_x86_64::Registers_x86_64(const void *registers) { @@ -442,6 +478,38 @@ inline const char *Registers_x86_64::getRegisterName(int regNum) { return "r14"; case UNW_X86_64_R15: return "r15"; + case UNW_X86_64_XMM0: + return "xmm0"; + case UNW_X86_64_XMM1: + return "xmm1"; + case UNW_X86_64_XMM2: + return "xmm2"; + case UNW_X86_64_XMM3: + return "xmm3"; + case UNW_X86_64_XMM4: + return "xmm4"; + case UNW_X86_64_XMM5: + return "xmm5"; + case UNW_X86_64_XMM6: + return "xmm6"; + case UNW_X86_64_XMM7: + return "xmm7"; + case UNW_X86_64_XMM8: + return "xmm8"; + case UNW_X86_64_XMM9: + return "xmm9"; + case UNW_X86_64_XMM10: + return "xmm10"; + case UNW_X86_64_XMM11: + return "xmm11"; + case UNW_X86_64_XMM12: + return "xmm12"; + case UNW_X86_64_XMM13: + return "xmm13"; + case UNW_X86_64_XMM14: + return "xmm14"; + case UNW_X86_64_XMM15: + return "xmm15"; default: return "unknown register"; } @@ -455,12 +523,37 @@ inline void Registers_x86_64::setFloatRegister(int, double) { _LIBUNWIND_ABORT("no x86_64 float registers"); } -inline v128 Registers_x86_64::getVectorRegister(int) const { - _LIBUNWIND_ABORT("no x86_64 vector registers"); +inline bool Registers_x86_64::validVectorRegister(int regNum) const { +#if defined(_WIN64) + if (regNum < UNW_X86_64_XMM0) + return false; + if (regNum > UNW_X86_64_XMM15) + return false; + return true; +#else + (void)regNum; // suppress unused parameter warning + return false; +#endif } -inline void Registers_x86_64::setVectorRegister(int, v128) { +inline v128 Registers_x86_64::getVectorRegister(int regNum) const { +#if defined(_WIN64) + assert(validVectorRegister(regNum)); + return _xmm[regNum - UNW_X86_64_XMM0]; +#else + (void)regNum; // suppress unused parameter warning _LIBUNWIND_ABORT("no x86_64 vector registers"); +#endif +} + +inline void Registers_x86_64::setVectorRegister(int regNum, v128 value) { +#if defined(_WIN64) + assert(validVectorRegister(regNum)); + _xmm[regNum - UNW_X86_64_XMM0] = value; +#else + (void)regNum; (void)value; // suppress unused parameter warnings + _LIBUNWIND_ABORT("no x86_64 vector registers"); +#endif } #endif // _LIBUNWIND_TARGET_X86_64 @@ -482,9 +575,10 @@ class _LIBUNWIND_HIDDEN Registers_ppc { bool validVectorRegister(int num) const; v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); - const char *getRegisterName(int num); + static const char *getRegisterName(int num); void jumpto(); - static int lastDwarfRegNum() { return 112; } + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC; } + static int getArch() { return REGISTERS_PPC; } uint64_t getSP() const { return _registers.__r1; } void setSP(uint32_t value) { _registers.__r1 = value; } @@ -1030,6 +1124,648 @@ inline const char *Registers_ppc::getRegisterName(int regNum) { } #endif // _LIBUNWIND_TARGET_PPC +#if defined(_LIBUNWIND_TARGET_PPC64) +/// Registers_ppc64 holds the register state of a thread in a 64-bit PowerPC +/// process. +class _LIBUNWIND_HIDDEN Registers_ppc64 { +public: + Registers_ppc64(); + Registers_ppc64(const void *registers); + + bool validRegister(int num) const; + uint64_t getRegister(int num) const; + void setRegister(int num, uint64_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto(); + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64; } + static int getArch() { return REGISTERS_PPC64; } + + uint64_t getSP() const { return _registers.__r1; } + void setSP(uint64_t value) { _registers.__r1 = value; } + uint64_t getIP() const { return _registers.__srr0; } + void setIP(uint64_t value) { _registers.__srr0 = value; } + +private: + struct ppc64_thread_state_t { + uint64_t __srr0; // Instruction address register (PC) + uint64_t __srr1; // Machine state register (supervisor) + uint64_t __r0; + uint64_t __r1; + uint64_t __r2; + uint64_t __r3; + uint64_t __r4; + uint64_t __r5; + uint64_t __r6; + uint64_t __r7; + 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 __r16; + uint64_t __r17; + uint64_t __r18; + uint64_t __r19; + uint64_t __r20; + uint64_t __r21; + uint64_t __r22; + uint64_t __r23; + uint64_t __r24; + uint64_t __r25; + uint64_t __r26; + uint64_t __r27; + uint64_t __r28; + uint64_t __r29; + uint64_t __r30; + uint64_t __r31; + uint64_t __cr; // Condition register + uint64_t __xer; // User's integer exception register + uint64_t __lr; // Link register + uint64_t __ctr; // Count register + uint64_t __vrsave; // Vector Save Register + }; + + union ppc64_vsr_t { + struct asfloat_s { + double f; + uint64_t v2; + } asfloat; + v128 v; + }; + + ppc64_thread_state_t _registers; + ppc64_vsr_t _vectorScalarRegisters[64]; + + static int getVectorRegNum(int num); +}; + +inline Registers_ppc64::Registers_ppc64(const void *registers) { + static_assert((check_fit::does_fit), + "ppc64 registers do not fit into unw_context_t"); + memcpy(&_registers, static_cast(registers), + sizeof(_registers)); + static_assert(sizeof(_registers) == 312, + "expected vector scalar register offset to be 312"); + memcpy(&_vectorScalarRegisters, + static_cast(registers) + sizeof(_registers), + sizeof(_vectorScalarRegisters)); + static_assert(sizeof(_registers) + + sizeof(_vectorScalarRegisters) == 1336, + "expected vector register offset to be 1336 bytes"); +} + +inline Registers_ppc64::Registers_ppc64() { + memset(&_registers, 0, sizeof(_registers)); + memset(&_vectorScalarRegisters, 0, sizeof(_vectorScalarRegisters)); +} + +inline bool Registers_ppc64::validRegister(int regNum) const { + switch (regNum) { + case UNW_REG_IP: + case UNW_REG_SP: + case UNW_PPC64_XER: + case UNW_PPC64_LR: + case UNW_PPC64_CTR: + case UNW_PPC64_VRSAVE: + return true; + } + + if (regNum >= UNW_PPC64_R0 && regNum <= UNW_PPC64_R31) + return true; + if (regNum >= UNW_PPC64_CR0 && regNum <= UNW_PPC64_CR7) + return true; + + return false; +} + +inline uint64_t Registers_ppc64::getRegister(int regNum) const { + switch (regNum) { + case UNW_REG_IP: + return _registers.__srr0; + case UNW_PPC64_R0: + return _registers.__r0; + case UNW_PPC64_R1: + case UNW_REG_SP: + return _registers.__r1; + case UNW_PPC64_R2: + return _registers.__r2; + case UNW_PPC64_R3: + return _registers.__r3; + case UNW_PPC64_R4: + return _registers.__r4; + case UNW_PPC64_R5: + return _registers.__r5; + case UNW_PPC64_R6: + return _registers.__r6; + case UNW_PPC64_R7: + return _registers.__r7; + case UNW_PPC64_R8: + return _registers.__r8; + case UNW_PPC64_R9: + return _registers.__r9; + case UNW_PPC64_R10: + return _registers.__r10; + case UNW_PPC64_R11: + return _registers.__r11; + case UNW_PPC64_R12: + return _registers.__r12; + case UNW_PPC64_R13: + return _registers.__r13; + case UNW_PPC64_R14: + return _registers.__r14; + case UNW_PPC64_R15: + return _registers.__r15; + case UNW_PPC64_R16: + return _registers.__r16; + case UNW_PPC64_R17: + return _registers.__r17; + case UNW_PPC64_R18: + return _registers.__r18; + case UNW_PPC64_R19: + return _registers.__r19; + case UNW_PPC64_R20: + return _registers.__r20; + case UNW_PPC64_R21: + return _registers.__r21; + case UNW_PPC64_R22: + return _registers.__r22; + case UNW_PPC64_R23: + return _registers.__r23; + case UNW_PPC64_R24: + return _registers.__r24; + case UNW_PPC64_R25: + return _registers.__r25; + case UNW_PPC64_R26: + return _registers.__r26; + case UNW_PPC64_R27: + return _registers.__r27; + case UNW_PPC64_R28: + return _registers.__r28; + case UNW_PPC64_R29: + return _registers.__r29; + case UNW_PPC64_R30: + return _registers.__r30; + case UNW_PPC64_R31: + return _registers.__r31; + case UNW_PPC64_CR0: + return (_registers.__cr & 0xF0000000); + case UNW_PPC64_CR1: + return (_registers.__cr & 0x0F000000); + case UNW_PPC64_CR2: + return (_registers.__cr & 0x00F00000); + case UNW_PPC64_CR3: + return (_registers.__cr & 0x000F0000); + case UNW_PPC64_CR4: + return (_registers.__cr & 0x0000F000); + case UNW_PPC64_CR5: + return (_registers.__cr & 0x00000F00); + case UNW_PPC64_CR6: + return (_registers.__cr & 0x000000F0); + case UNW_PPC64_CR7: + return (_registers.__cr & 0x0000000F); + case UNW_PPC64_XER: + return _registers.__xer; + case UNW_PPC64_LR: + return _registers.__lr; + case UNW_PPC64_CTR: + return _registers.__ctr; + case UNW_PPC64_VRSAVE: + return _registers.__vrsave; + } + _LIBUNWIND_ABORT("unsupported ppc64 register"); +} + +inline void Registers_ppc64::setRegister(int regNum, uint64_t value) { + switch (regNum) { + case UNW_REG_IP: + _registers.__srr0 = value; + return; + case UNW_PPC64_R0: + _registers.__r0 = value; + return; + case UNW_PPC64_R1: + case UNW_REG_SP: + _registers.__r1 = value; + return; + case UNW_PPC64_R2: + _registers.__r2 = value; + return; + case UNW_PPC64_R3: + _registers.__r3 = value; + return; + case UNW_PPC64_R4: + _registers.__r4 = value; + return; + case UNW_PPC64_R5: + _registers.__r5 = value; + return; + case UNW_PPC64_R6: + _registers.__r6 = value; + return; + case UNW_PPC64_R7: + _registers.__r7 = value; + return; + case UNW_PPC64_R8: + _registers.__r8 = value; + return; + case UNW_PPC64_R9: + _registers.__r9 = value; + return; + case UNW_PPC64_R10: + _registers.__r10 = value; + return; + case UNW_PPC64_R11: + _registers.__r11 = value; + return; + case UNW_PPC64_R12: + _registers.__r12 = value; + return; + case UNW_PPC64_R13: + _registers.__r13 = value; + return; + case UNW_PPC64_R14: + _registers.__r14 = value; + return; + case UNW_PPC64_R15: + _registers.__r15 = value; + return; + case UNW_PPC64_R16: + _registers.__r16 = value; + return; + case UNW_PPC64_R17: + _registers.__r17 = value; + return; + case UNW_PPC64_R18: + _registers.__r18 = value; + return; + case UNW_PPC64_R19: + _registers.__r19 = value; + return; + case UNW_PPC64_R20: + _registers.__r20 = value; + return; + case UNW_PPC64_R21: + _registers.__r21 = value; + return; + case UNW_PPC64_R22: + _registers.__r22 = value; + return; + case UNW_PPC64_R23: + _registers.__r23 = value; + return; + case UNW_PPC64_R24: + _registers.__r24 = value; + return; + case UNW_PPC64_R25: + _registers.__r25 = value; + return; + case UNW_PPC64_R26: + _registers.__r26 = value; + return; + case UNW_PPC64_R27: + _registers.__r27 = value; + return; + case UNW_PPC64_R28: + _registers.__r28 = value; + return; + case UNW_PPC64_R29: + _registers.__r29 = value; + return; + case UNW_PPC64_R30: + _registers.__r30 = value; + return; + case UNW_PPC64_R31: + _registers.__r31 = value; + return; + case UNW_PPC64_CR0: + _registers.__cr &= 0x0FFFFFFF; + _registers.__cr |= (value & 0xF0000000); + return; + case UNW_PPC64_CR1: + _registers.__cr &= 0xF0FFFFFF; + _registers.__cr |= (value & 0x0F000000); + return; + case UNW_PPC64_CR2: + _registers.__cr &= 0xFF0FFFFF; + _registers.__cr |= (value & 0x00F00000); + return; + case UNW_PPC64_CR3: + _registers.__cr &= 0xFFF0FFFF; + _registers.__cr |= (value & 0x000F0000); + return; + case UNW_PPC64_CR4: + _registers.__cr &= 0xFFFF0FFF; + _registers.__cr |= (value & 0x0000F000); + return; + case UNW_PPC64_CR5: + _registers.__cr &= 0xFFFFF0FF; + _registers.__cr |= (value & 0x00000F00); + return; + case UNW_PPC64_CR6: + _registers.__cr &= 0xFFFFFF0F; + _registers.__cr |= (value & 0x000000F0); + return; + case UNW_PPC64_CR7: + _registers.__cr &= 0xFFFFFFF0; + _registers.__cr |= (value & 0x0000000F); + return; + case UNW_PPC64_XER: + _registers.__xer = value; + return; + case UNW_PPC64_LR: + _registers.__lr = value; + return; + case UNW_PPC64_CTR: + _registers.__ctr = value; + return; + case UNW_PPC64_VRSAVE: + _registers.__vrsave = value; + return; + } + _LIBUNWIND_ABORT("unsupported ppc64 register"); +} + +inline bool Registers_ppc64::validFloatRegister(int regNum) const { + return regNum >= UNW_PPC64_F0 && regNum <= UNW_PPC64_F31; +} + +inline double Registers_ppc64::getFloatRegister(int regNum) const { + assert(validFloatRegister(regNum)); + return _vectorScalarRegisters[regNum - UNW_PPC64_F0].asfloat.f; +} + +inline void Registers_ppc64::setFloatRegister(int regNum, double value) { + assert(validFloatRegister(regNum)); + _vectorScalarRegisters[regNum - UNW_PPC64_F0].asfloat.f = value; +} + +inline bool Registers_ppc64::validVectorRegister(int regNum) const { +#ifdef PPC64_HAS_VMX + if (regNum >= UNW_PPC64_VS0 && regNum <= UNW_PPC64_VS31) + return true; + if (regNum >= UNW_PPC64_VS32 && regNum <= UNW_PPC64_VS63) + return true; +#else + if (regNum >= UNW_PPC64_V0 && regNum <= UNW_PPC64_V31) + return true; +#endif + return false; +} + +inline int Registers_ppc64::getVectorRegNum(int num) +{ + if (num >= UNW_PPC64_VS0 && num <= UNW_PPC64_VS31) + return num - UNW_PPC64_VS0; + else + return num - UNW_PPC64_VS32 + 32; +} + +inline v128 Registers_ppc64::getVectorRegister(int regNum) const { + assert(validVectorRegister(regNum)); + return _vectorScalarRegisters[getVectorRegNum(regNum)].v; +} + +inline void Registers_ppc64::setVectorRegister(int regNum, v128 value) { + assert(validVectorRegister(regNum)); + _vectorScalarRegisters[getVectorRegNum(regNum)].v = value; +} + +inline const char *Registers_ppc64::getRegisterName(int regNum) { + switch (regNum) { + case UNW_REG_IP: + return "ip"; + case UNW_REG_SP: + return "sp"; + case UNW_PPC64_R0: + return "r0"; + case UNW_PPC64_R1: + return "r1"; + case UNW_PPC64_R2: + return "r2"; + case UNW_PPC64_R3: + return "r3"; + case UNW_PPC64_R4: + return "r4"; + case UNW_PPC64_R5: + return "r5"; + case UNW_PPC64_R6: + return "r6"; + case UNW_PPC64_R7: + return "r7"; + case UNW_PPC64_R8: + return "r8"; + case UNW_PPC64_R9: + return "r9"; + case UNW_PPC64_R10: + return "r10"; + case UNW_PPC64_R11: + return "r11"; + case UNW_PPC64_R12: + return "r12"; + case UNW_PPC64_R13: + return "r13"; + case UNW_PPC64_R14: + return "r14"; + case UNW_PPC64_R15: + return "r15"; + case UNW_PPC64_R16: + return "r16"; + case UNW_PPC64_R17: + return "r17"; + case UNW_PPC64_R18: + return "r18"; + case UNW_PPC64_R19: + return "r19"; + case UNW_PPC64_R20: + return "r20"; + case UNW_PPC64_R21: + return "r21"; + case UNW_PPC64_R22: + return "r22"; + case UNW_PPC64_R23: + return "r23"; + case UNW_PPC64_R24: + return "r24"; + case UNW_PPC64_R25: + return "r25"; + case UNW_PPC64_R26: + return "r26"; + case UNW_PPC64_R27: + return "r27"; + case UNW_PPC64_R28: + return "r28"; + case UNW_PPC64_R29: + return "r29"; + case UNW_PPC64_R30: + return "r30"; + case UNW_PPC64_R31: + return "r31"; + case UNW_PPC64_CR0: + return "cr0"; + case UNW_PPC64_CR1: + return "cr1"; + case UNW_PPC64_CR2: + return "cr2"; + case UNW_PPC64_CR3: + return "cr3"; + case UNW_PPC64_CR4: + return "cr4"; + case UNW_PPC64_CR5: + return "cr5"; + case UNW_PPC64_CR6: + return "cr6"; + case UNW_PPC64_CR7: + return "cr7"; + case UNW_PPC64_XER: + return "xer"; + case UNW_PPC64_LR: + return "lr"; + case UNW_PPC64_CTR: + return "ctr"; + case UNW_PPC64_VRSAVE: + return "vrsave"; + case UNW_PPC64_F0: + return "fp0"; + case UNW_PPC64_F1: + return "fp1"; + case UNW_PPC64_F2: + return "fp2"; + case UNW_PPC64_F3: + return "fp3"; + case UNW_PPC64_F4: + return "fp4"; + case UNW_PPC64_F5: + return "fp5"; + case UNW_PPC64_F6: + return "fp6"; + case UNW_PPC64_F7: + return "fp7"; + case UNW_PPC64_F8: + return "fp8"; + case UNW_PPC64_F9: + return "fp9"; + case UNW_PPC64_F10: + return "fp10"; + case UNW_PPC64_F11: + return "fp11"; + case UNW_PPC64_F12: + return "fp12"; + case UNW_PPC64_F13: + return "fp13"; + case UNW_PPC64_F14: + return "fp14"; + case UNW_PPC64_F15: + return "fp15"; + case UNW_PPC64_F16: + return "fp16"; + case UNW_PPC64_F17: + return "fp17"; + case UNW_PPC64_F18: + return "fp18"; + case UNW_PPC64_F19: + return "fp19"; + case UNW_PPC64_F20: + return "fp20"; + case UNW_PPC64_F21: + return "fp21"; + case UNW_PPC64_F22: + return "fp22"; + case UNW_PPC64_F23: + return "fp23"; + case UNW_PPC64_F24: + return "fp24"; + case UNW_PPC64_F25: + return "fp25"; + case UNW_PPC64_F26: + return "fp26"; + case UNW_PPC64_F27: + return "fp27"; + case UNW_PPC64_F28: + return "fp28"; + case UNW_PPC64_F29: + return "fp29"; + case UNW_PPC64_F30: + return "fp30"; + case UNW_PPC64_F31: + return "fp31"; + case UNW_PPC64_V0: + return "v0"; + case UNW_PPC64_V1: + return "v1"; + case UNW_PPC64_V2: + return "v2"; + case UNW_PPC64_V3: + return "v3"; + case UNW_PPC64_V4: + return "v4"; + case UNW_PPC64_V5: + return "v5"; + case UNW_PPC64_V6: + return "v6"; + case UNW_PPC64_V7: + return "v7"; + case UNW_PPC64_V8: + return "v8"; + case UNW_PPC64_V9: + return "v9"; + case UNW_PPC64_V10: + return "v10"; + case UNW_PPC64_V11: + return "v11"; + case UNW_PPC64_V12: + return "v12"; + case UNW_PPC64_V13: + return "v13"; + case UNW_PPC64_V14: + return "v14"; + case UNW_PPC64_V15: + return "v15"; + case UNW_PPC64_V16: + return "v16"; + case UNW_PPC64_V17: + return "v17"; + case UNW_PPC64_V18: + return "v18"; + case UNW_PPC64_V19: + return "v19"; + case UNW_PPC64_V20: + return "v20"; + case UNW_PPC64_V21: + return "v21"; + case UNW_PPC64_V22: + return "v22"; + case UNW_PPC64_V23: + return "v23"; + case UNW_PPC64_V24: + return "v24"; + case UNW_PPC64_V25: + return "v25"; + case UNW_PPC64_V26: + return "v26"; + case UNW_PPC64_V27: + return "v27"; + case UNW_PPC64_V28: + return "v28"; + case UNW_PPC64_V29: + return "v29"; + case UNW_PPC64_V30: + return "v30"; + case UNW_PPC64_V31: + return "v31"; + } + return "unknown register"; +} +#endif // _LIBUNWIND_TARGET_PPC64 + #if defined(_LIBUNWIND_TARGET_AARCH64) /// Registers_arm64 holds the register state of a thread in a 64-bit arm @@ -1048,9 +1784,10 @@ class _LIBUNWIND_HIDDEN Registers_arm64 { bool validVectorRegister(int num) const; v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); - const char *getRegisterName(int num); + static const char *getRegisterName(int num); void jumpto(); - static int lastDwarfRegNum() { return 95; } + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64; } + static int getArch() { return REGISTERS_ARM64; } uint64_t getSP() const { return _registers.__sp; } void setSP(uint64_t value) { _registers.__sp = value; } @@ -1066,7 +1803,7 @@ class _LIBUNWIND_HIDDEN Registers_arm64 { uint64_t __lr; // Link register x30 uint64_t __sp; // Stack pointer x31 uint64_t __pc; // Program counter - uint64_t padding; // 16-byte align + uint64_t __ra_sign_state; // RA sign state register }; GPRs _registers; @@ -1102,6 +1839,8 @@ inline bool Registers_arm64::validRegister(int regNum) const { return false; if (regNum > 95) return false; + if (regNum == UNW_ARM64_RA_SIGN_STATE) + return true; if ((regNum > 31) && (regNum < 64)) return false; return true; @@ -1112,6 +1851,8 @@ inline uint64_t Registers_arm64::getRegister(int regNum) const { return _registers.__pc; if (regNum == UNW_REG_SP) return _registers.__sp; + if (regNum == UNW_ARM64_RA_SIGN_STATE) + return _registers.__ra_sign_state; if ((regNum >= 0) && (regNum < 32)) return _registers.__x[regNum]; _LIBUNWIND_ABORT("unsupported arm64 register"); @@ -1122,6 +1863,8 @@ inline void Registers_arm64::setRegister(int regNum, uint64_t value) { _registers.__pc = value; else if (regNum == UNW_REG_SP) _registers.__sp = value; + else if (regNum == UNW_ARM64_RA_SIGN_STATE) + _registers.__ra_sign_state = value; else if ((regNum >= 0) && (regNum < 32)) _registers.__x[regNum] = value; else @@ -1310,7 +2053,7 @@ class _LIBUNWIND_HIDDEN Registers_arm { Registers_arm(const void *registers); bool validRegister(int num) const; - uint32_t getRegister(int num); + uint32_t getRegister(int num) const; void setRegister(int num, uint32_t value); bool validFloatRegister(int num) const; unw_fpreg_t getFloatRegister(int num); @@ -1318,11 +2061,13 @@ class _LIBUNWIND_HIDDEN Registers_arm { bool validVectorRegister(int num) const; v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); - const char *getRegisterName(int num); + static const char *getRegisterName(int num); void jumpto() { restoreSavedFloatRegisters(); restoreCoreAndJumpTo(); } + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM; } + static int getArch() { return REGISTERS_ARM; } uint32_t getSP() const { return _registers.__sp; } void setSP(uint32_t value) { _registers.__sp = value; } @@ -1343,10 +2088,12 @@ class _LIBUNWIND_HIDDEN Registers_arm { } if (_saved_vfp_d16_d31) restoreVFPv3(_vfp_d16_d31); +#if defined(__ARM_WMMX) if (_saved_iwmmx) restoreiWMMX(_iwmmx); if (_saved_iwmmx_control) restoreiWMMXControl(_iwmmx_control); +#endif } private: @@ -1360,13 +2107,15 @@ class _LIBUNWIND_HIDDEN Registers_arm { static void saveVFPWithFSTMD(unw_fpreg_t*); static void saveVFPWithFSTMX(unw_fpreg_t*); static void saveVFPv3(unw_fpreg_t*); - static void saveiWMMX(unw_fpreg_t*); - static void saveiWMMXControl(uint32_t*); static void restoreVFPWithFLDMD(unw_fpreg_t*); static void restoreVFPWithFLDMX(unw_fpreg_t*); static void restoreVFPv3(unw_fpreg_t*); +#if defined(__ARM_WMMX) + static void saveiWMMX(unw_fpreg_t*); + static void saveiWMMXControl(uint32_t*); static void restoreiWMMX(unw_fpreg_t*); static void restoreiWMMXControl(uint32_t*); +#endif void restoreCoreAndJumpTo(); // ARM registers @@ -1384,47 +2133,53 @@ class _LIBUNWIND_HIDDEN Registers_arm { bool _saved_vfp_d0_d15; // Whether VFPv3 D16-D31 are saved. bool _saved_vfp_d16_d31; - // Whether iWMMX data registers are saved. - bool _saved_iwmmx; - // Whether iWMMX control registers are saved. - bool _saved_iwmmx_control; // VFP registers D0-D15, + padding if saved using FSTMX unw_fpreg_t _vfp_d0_d15_pad[17]; // VFPv3 registers D16-D31, always saved using FSTMD unw_fpreg_t _vfp_d16_d31[16]; +#if defined(__ARM_WMMX) + // Whether iWMMX data registers are saved. + bool _saved_iwmmx; + // Whether iWMMX control registers are saved. + mutable bool _saved_iwmmx_control; // iWMMX registers unw_fpreg_t _iwmmx[16]; // iWMMX control registers - uint32_t _iwmmx_control[4]; + mutable uint32_t _iwmmx_control[4]; +#endif }; inline Registers_arm::Registers_arm(const void *registers) : _use_X_for_vfp_save(false), _saved_vfp_d0_d15(false), - _saved_vfp_d16_d31(false), - _saved_iwmmx(false), - _saved_iwmmx_control(false) { + _saved_vfp_d16_d31(false) { static_assert((check_fit::does_fit), "arm registers do not fit into unw_context_t"); // See unw_getcontext() note about data. memcpy(&_registers, registers, sizeof(_registers)); memset(&_vfp_d0_d15_pad, 0, sizeof(_vfp_d0_d15_pad)); memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31)); +#if defined(__ARM_WMMX) + _saved_iwmmx = false; + _saved_iwmmx_control = false; memset(&_iwmmx, 0, sizeof(_iwmmx)); memset(&_iwmmx_control, 0, sizeof(_iwmmx_control)); +#endif } inline Registers_arm::Registers_arm() : _use_X_for_vfp_save(false), _saved_vfp_d0_d15(false), - _saved_vfp_d16_d31(false), - _saved_iwmmx(false), - _saved_iwmmx_control(false) { + _saved_vfp_d16_d31(false) { memset(&_registers, 0, sizeof(_registers)); memset(&_vfp_d0_d15_pad, 0, sizeof(_vfp_d0_d15_pad)); memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31)); +#if defined(__ARM_WMMX) + _saved_iwmmx = false; + _saved_iwmmx_control = false; memset(&_iwmmx, 0, sizeof(_iwmmx)); memset(&_iwmmx_control, 0, sizeof(_iwmmx_control)); +#endif } inline bool Registers_arm::validRegister(int regNum) const { @@ -1432,24 +2187,35 @@ inline bool Registers_arm::validRegister(int regNum) const { // virtual register set (VRS). if (regNum == UNW_REG_IP) return true; + if (regNum == UNW_REG_SP) return true; + if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R15) return true; + +#if defined(__ARM_WMMX) if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) return true; +#endif + return false; } -inline uint32_t Registers_arm::getRegister(int regNum) { +inline uint32_t Registers_arm::getRegister(int regNum) const { if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP) return _registers.__sp; + if (regNum == UNW_ARM_LR) return _registers.__lr; + if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP) return _registers.__pc; + if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R12) return _registers.__r[regNum]; + +#if defined(__ARM_WMMX) if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) { if (!_saved_iwmmx_control) { _saved_iwmmx_control = true; @@ -1457,26 +2223,44 @@ inline uint32_t Registers_arm::getRegister(int regNum) { } return _iwmmx_control[regNum - UNW_ARM_WC0]; } +#endif + _LIBUNWIND_ABORT("unsupported arm register"); } inline void Registers_arm::setRegister(int regNum, uint32_t value) { - if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP) + if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP) { _registers.__sp = value; - else if (regNum == UNW_ARM_LR) + return; + } + + if (regNum == UNW_ARM_LR) { _registers.__lr = value; - else if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP) + return; + } + + if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP) { _registers.__pc = value; - else if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R12) + return; + } + + if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R12) { _registers.__r[regNum] = value; - else if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) { + return; + } + +#if defined(__ARM_WMMX) + if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) { if (!_saved_iwmmx_control) { _saved_iwmmx_control = true; saveiWMMXControl(_iwmmx_control); } _iwmmx_control[regNum - UNW_ARM_WC0] = value; - } else - _LIBUNWIND_ABORT("unsupported arm register"); + return; + } +#endif + + _LIBUNWIND_ABORT("unsupported arm register"); } inline const char *Registers_arm::getRegisterName(int regNum) { @@ -1652,7 +2436,10 @@ inline bool Registers_arm::validFloatRegister(int regNum) const { // NOTE: Consider the intel MMX registers floating points so the // unw_get_fpreg can be used to transmit the 64-bit data back. return ((regNum >= UNW_ARM_D0) && (regNum <= UNW_ARM_D31)) - || ((regNum >= UNW_ARM_WR0) && (regNum <= UNW_ARM_WR15)); +#if defined(__ARM_WMMX) + || ((regNum >= UNW_ARM_WR0) && (regNum <= UNW_ARM_WR15)) +#endif + ; } inline unw_fpreg_t Registers_arm::getFloatRegister(int regNum) { @@ -1665,21 +2452,27 @@ inline unw_fpreg_t Registers_arm::getFloatRegister(int regNum) { saveVFPWithFSTMD(_vfp_d0_d15_pad); } return _vfp_d0_d15_pad[regNum - UNW_ARM_D0]; - } else if (regNum >= UNW_ARM_D16 && regNum <= UNW_ARM_D31) { + } + + if (regNum >= UNW_ARM_D16 && regNum <= UNW_ARM_D31) { if (!_saved_vfp_d16_d31) { _saved_vfp_d16_d31 = true; saveVFPv3(_vfp_d16_d31); } return _vfp_d16_d31[regNum - UNW_ARM_D16]; - } else if (regNum >= UNW_ARM_WR0 && regNum <= UNW_ARM_WR15) { + } + +#if defined(__ARM_WMMX) + if (regNum >= UNW_ARM_WR0 && regNum <= UNW_ARM_WR15) { if (!_saved_iwmmx) { _saved_iwmmx = true; saveiWMMX(_iwmmx); } return _iwmmx[regNum - UNW_ARM_WR0]; - } else { - _LIBUNWIND_ABORT("Unknown ARM float register"); } +#endif + + _LIBUNWIND_ABORT("Unknown ARM float register"); } inline void Registers_arm::setFloatRegister(int regNum, unw_fpreg_t value) { @@ -1692,21 +2485,30 @@ inline void Registers_arm::setFloatRegister(int regNum, unw_fpreg_t value) { saveVFPWithFSTMD(_vfp_d0_d15_pad); } _vfp_d0_d15_pad[regNum - UNW_ARM_D0] = value; - } else if (regNum >= UNW_ARM_D16 && regNum <= UNW_ARM_D31) { + return; + } + + if (regNum >= UNW_ARM_D16 && regNum <= UNW_ARM_D31) { if (!_saved_vfp_d16_d31) { _saved_vfp_d16_d31 = true; saveVFPv3(_vfp_d16_d31); } _vfp_d16_d31[regNum - UNW_ARM_D16] = value; - } else if (regNum >= UNW_ARM_WR0 && regNum <= UNW_ARM_WR15) { + return; + } + +#if defined(__ARM_WMMX) + if (regNum >= UNW_ARM_WR0 && regNum <= UNW_ARM_WR15) { if (!_saved_iwmmx) { _saved_iwmmx = true; saveiWMMX(_iwmmx); } _iwmmx[regNum - UNW_ARM_WR0] = value; - } else { - _LIBUNWIND_ABORT("Unknown ARM float register"); + return; } +#endif + + _LIBUNWIND_ABORT("Unknown ARM float register"); } inline bool Registers_arm::validVectorRegister(int) const { @@ -1740,18 +2542,21 @@ class _LIBUNWIND_HIDDEN Registers_or1k { bool validVectorRegister(int num) const; v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); - const char *getRegisterName(int num); + static const char *getRegisterName(int num); void jumpto(); - static int lastDwarfRegNum() { return 31; } + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K; } + static int getArch() { return REGISTERS_OR1K; } uint64_t getSP() const { return _registers.__r[1]; } void setSP(uint32_t value) { _registers.__r[1] = value; } - uint64_t getIP() const { return _registers.__r[9]; } - void setIP(uint32_t value) { _registers.__r[9] = value; } + uint64_t getIP() const { return _registers.__pc; } + void setIP(uint32_t value) { _registers.__pc = value; } private: struct or1k_thread_state_t { - unsigned int __r[32]; + unsigned int __r[32]; // r0-r31 + unsigned int __pc; // Program counter + unsigned int __epcr; // Program counter at exception }; or1k_thread_state_t _registers; @@ -1777,6 +2582,8 @@ inline bool Registers_or1k::validRegister(int regNum) const { return false; if (regNum <= UNW_OR1K_R31) return true; + if (regNum == UNW_OR1K_EPCR) + return true; return false; } @@ -1786,9 +2593,11 @@ inline uint32_t Registers_or1k::getRegister(int regNum) const { switch (regNum) { case UNW_REG_IP: - return _registers.__r[9]; + return _registers.__pc; case UNW_REG_SP: return _registers.__r[1]; + case UNW_OR1K_EPCR: + return _registers.__epcr; } _LIBUNWIND_ABORT("unsupported or1k register"); } @@ -1801,11 +2610,14 @@ inline void Registers_or1k::setRegister(int regNum, uint32_t value) { switch (regNum) { case UNW_REG_IP: - _registers.__r[9] = value; + _registers.__pc = value; return; case UNW_REG_SP: _registers.__r[1] = value; return; + case UNW_OR1K_EPCR: + _registers.__epcr = value; + return; } _LIBUNWIND_ABORT("unsupported or1k register"); } @@ -1901,12 +2713,811 @@ inline const char *Registers_or1k::getRegisterName(int regNum) { return "r30"; case UNW_OR1K_R31: return "r31"; + case UNW_OR1K_EPCR: + return "EPCR"; default: return "unknown register"; } } #endif // _LIBUNWIND_TARGET_OR1K + +#if defined(_LIBUNWIND_TARGET_MIPS_O32) +/// Registers_mips_o32 holds the register state of a thread in a 32-bit MIPS +/// process. +class _LIBUNWIND_HIDDEN Registers_mips_o32 { +public: + Registers_mips_o32(); + Registers_mips_o32(const void *registers); + + bool validRegister(int num) const; + uint32_t getRegister(int num) const; + void setRegister(int num, uint32_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto(); + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS; } + static int getArch() { return REGISTERS_MIPS_O32; } + + uint32_t getSP() const { return _registers.__r[29]; } + void setSP(uint32_t value) { _registers.__r[29] = value; } + uint32_t getIP() const { return _registers.__pc; } + void setIP(uint32_t value) { _registers.__pc = value; } + +private: + struct mips_o32_thread_state_t { + uint32_t __r[32]; + uint32_t __pc; + uint32_t __hi; + uint32_t __lo; + }; + + mips_o32_thread_state_t _registers; +#ifdef __mips_hard_float + /// O32 with 32-bit floating point registers only uses half of this + /// space. However, using the same layout for 32-bit vs 64-bit + /// floating point registers results in a single context size for + /// O32 with hard float. + uint32_t _padding; + double _floats[32]; +#endif +}; + +inline Registers_mips_o32::Registers_mips_o32(const void *registers) { + static_assert((check_fit::does_fit), + "mips_o32 registers do not fit into unw_context_t"); + memcpy(&_registers, static_cast(registers), + sizeof(_registers)); +} + +inline Registers_mips_o32::Registers_mips_o32() { + memset(&_registers, 0, sizeof(_registers)); +} + +inline bool Registers_mips_o32::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum < 0) + return false; + if (regNum <= UNW_MIPS_R31) + return true; +#if __mips_isa_rev != 6 + if (regNum == UNW_MIPS_HI) + return true; + if (regNum == UNW_MIPS_LO) + return true; +#endif +#if defined(__mips_hard_float) && __mips_fpr == 32 + if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) + return true; +#endif + // FIXME: DSP accumulator registers, MSA registers + return false; +} + +inline uint32_t Registers_mips_o32::getRegister(int regNum) const { + if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31) + return _registers.__r[regNum - UNW_MIPS_R0]; +#if defined(__mips_hard_float) && __mips_fpr == 32 + if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) { + uint32_t *p; + + if (regNum % 2 == 0) + p = (uint32_t *)&_floats[regNum - UNW_MIPS_F0]; + else + p = (uint32_t *)&_floats[(regNum - 1) - UNW_MIPS_F0] + 1; + return *p; + } +#endif + + switch (regNum) { + case UNW_REG_IP: + return _registers.__pc; + case UNW_REG_SP: + return _registers.__r[29]; + case UNW_MIPS_HI: + return _registers.__hi; + case UNW_MIPS_LO: + return _registers.__lo; + } + _LIBUNWIND_ABORT("unsupported mips_o32 register"); +} + +inline void Registers_mips_o32::setRegister(int regNum, uint32_t value) { + if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31) { + _registers.__r[regNum - UNW_MIPS_R0] = value; + return; + } +#if defined(__mips_hard_float) && __mips_fpr == 32 + if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) { + uint32_t *p; + + if (regNum % 2 == 0) + p = (uint32_t *)&_floats[regNum - UNW_MIPS_F0]; + else + p = (uint32_t *)&_floats[(regNum - 1) - UNW_MIPS_F0] + 1; + *p = value; + return; + } +#endif + + switch (regNum) { + case UNW_REG_IP: + _registers.__pc = value; + return; + case UNW_REG_SP: + _registers.__r[29] = value; + return; + case UNW_MIPS_HI: + _registers.__hi = value; + return; + case UNW_MIPS_LO: + _registers.__lo = value; + return; + } + _LIBUNWIND_ABORT("unsupported mips_o32 register"); +} + +inline bool Registers_mips_o32::validFloatRegister(int regNum) const { +#if defined(__mips_hard_float) && __mips_fpr == 64 + if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) + return true; +#endif + return false; +} + +inline double Registers_mips_o32::getFloatRegister(int regNum) const { +#if defined(__mips_hard_float) && __mips_fpr == 64 + assert(validFloatRegister(regNum)); + return _floats[regNum - UNW_MIPS_F0]; +#else + _LIBUNWIND_ABORT("mips_o32 float support not implemented"); +#endif +} + +inline void Registers_mips_o32::setFloatRegister(int regNum, + double value) { +#if defined(__mips_hard_float) && __mips_fpr == 64 + assert(validFloatRegister(regNum)); + _floats[regNum - UNW_MIPS_F0] = value; +#else + _LIBUNWIND_ABORT("mips_o32 float support not implemented"); +#endif +} + +inline bool Registers_mips_o32::validVectorRegister(int /* regNum */) const { + return false; +} + +inline v128 Registers_mips_o32::getVectorRegister(int /* regNum */) const { + _LIBUNWIND_ABORT("mips_o32 vector support not implemented"); +} + +inline void Registers_mips_o32::setVectorRegister(int /* regNum */, v128 /* value */) { + _LIBUNWIND_ABORT("mips_o32 vector support not implemented"); +} + +inline const char *Registers_mips_o32::getRegisterName(int regNum) { + switch (regNum) { + case UNW_MIPS_R0: + return "$0"; + case UNW_MIPS_R1: + return "$1"; + case UNW_MIPS_R2: + return "$2"; + case UNW_MIPS_R3: + return "$3"; + case UNW_MIPS_R4: + return "$4"; + case UNW_MIPS_R5: + return "$5"; + case UNW_MIPS_R6: + return "$6"; + case UNW_MIPS_R7: + return "$7"; + case UNW_MIPS_R8: + return "$8"; + case UNW_MIPS_R9: + return "$9"; + case UNW_MIPS_R10: + return "$10"; + case UNW_MIPS_R11: + return "$11"; + case UNW_MIPS_R12: + return "$12"; + case UNW_MIPS_R13: + return "$13"; + case UNW_MIPS_R14: + return "$14"; + case UNW_MIPS_R15: + return "$15"; + case UNW_MIPS_R16: + return "$16"; + case UNW_MIPS_R17: + return "$17"; + case UNW_MIPS_R18: + return "$18"; + case UNW_MIPS_R19: + return "$19"; + case UNW_MIPS_R20: + return "$20"; + case UNW_MIPS_R21: + return "$21"; + case UNW_MIPS_R22: + return "$22"; + case UNW_MIPS_R23: + return "$23"; + case UNW_MIPS_R24: + return "$24"; + case UNW_MIPS_R25: + return "$25"; + case UNW_MIPS_R26: + return "$26"; + case UNW_MIPS_R27: + return "$27"; + case UNW_MIPS_R28: + return "$28"; + case UNW_MIPS_R29: + return "$29"; + case UNW_MIPS_R30: + return "$30"; + case UNW_MIPS_R31: + return "$31"; + case UNW_MIPS_F0: + return "$f0"; + case UNW_MIPS_F1: + return "$f1"; + case UNW_MIPS_F2: + return "$f2"; + case UNW_MIPS_F3: + return "$f3"; + case UNW_MIPS_F4: + return "$f4"; + case UNW_MIPS_F5: + return "$f5"; + case UNW_MIPS_F6: + return "$f6"; + case UNW_MIPS_F7: + return "$f7"; + case UNW_MIPS_F8: + return "$f8"; + case UNW_MIPS_F9: + return "$f9"; + case UNW_MIPS_F10: + return "$f10"; + case UNW_MIPS_F11: + return "$f11"; + case UNW_MIPS_F12: + return "$f12"; + case UNW_MIPS_F13: + return "$f13"; + case UNW_MIPS_F14: + return "$f14"; + case UNW_MIPS_F15: + return "$f15"; + case UNW_MIPS_F16: + return "$f16"; + case UNW_MIPS_F17: + return "$f17"; + case UNW_MIPS_F18: + return "$f18"; + case UNW_MIPS_F19: + return "$f19"; + case UNW_MIPS_F20: + return "$f20"; + case UNW_MIPS_F21: + return "$f21"; + case UNW_MIPS_F22: + return "$f22"; + case UNW_MIPS_F23: + return "$f23"; + case UNW_MIPS_F24: + return "$f24"; + case UNW_MIPS_F25: + return "$f25"; + case UNW_MIPS_F26: + return "$f26"; + case UNW_MIPS_F27: + return "$f27"; + case UNW_MIPS_F28: + return "$f28"; + case UNW_MIPS_F29: + return "$f29"; + case UNW_MIPS_F30: + return "$f30"; + case UNW_MIPS_F31: + return "$f31"; + case UNW_MIPS_HI: + return "$hi"; + case UNW_MIPS_LO: + return "$lo"; + default: + return "unknown register"; + } +} +#endif // _LIBUNWIND_TARGET_MIPS_O32 + +#if defined(_LIBUNWIND_TARGET_MIPS_NEWABI) +/// Registers_mips_newabi holds the register state of a thread in a +/// MIPS process using NEWABI (the N32 or N64 ABIs). +class _LIBUNWIND_HIDDEN Registers_mips_newabi { +public: + Registers_mips_newabi(); + Registers_mips_newabi(const void *registers); + + bool validRegister(int num) const; + uint64_t getRegister(int num) const; + void setRegister(int num, uint64_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto(); + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS; } + static int getArch() { return REGISTERS_MIPS_NEWABI; } + + uint64_t getSP() const { return _registers.__r[29]; } + void setSP(uint64_t value) { _registers.__r[29] = value; } + uint64_t getIP() const { return _registers.__pc; } + void setIP(uint64_t value) { _registers.__pc = value; } + +private: + struct mips_newabi_thread_state_t { + uint64_t __r[32]; + uint64_t __pc; + uint64_t __hi; + uint64_t __lo; + }; + + mips_newabi_thread_state_t _registers; +#ifdef __mips_hard_float + double _floats[32]; +#endif +}; + +inline Registers_mips_newabi::Registers_mips_newabi(const void *registers) { + static_assert((check_fit::does_fit), + "mips_newabi registers do not fit into unw_context_t"); + memcpy(&_registers, static_cast(registers), + sizeof(_registers)); +} + +inline Registers_mips_newabi::Registers_mips_newabi() { + memset(&_registers, 0, sizeof(_registers)); +} + +inline bool Registers_mips_newabi::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum < 0) + return false; + if (regNum <= UNW_MIPS_R31) + return true; +#if __mips_isa_rev != 6 + if (regNum == UNW_MIPS_HI) + return true; + if (regNum == UNW_MIPS_LO) + return true; +#endif + // FIXME: Hard float, DSP accumulator registers, MSA registers + return false; +} + +inline uint64_t Registers_mips_newabi::getRegister(int regNum) const { + if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31) + return _registers.__r[regNum - UNW_MIPS_R0]; + + switch (regNum) { + case UNW_REG_IP: + return _registers.__pc; + case UNW_REG_SP: + return _registers.__r[29]; + case UNW_MIPS_HI: + return _registers.__hi; + case UNW_MIPS_LO: + return _registers.__lo; + } + _LIBUNWIND_ABORT("unsupported mips_newabi register"); +} + +inline void Registers_mips_newabi::setRegister(int regNum, uint64_t value) { + if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31) { + _registers.__r[regNum - UNW_MIPS_R0] = value; + return; + } + + switch (regNum) { + case UNW_REG_IP: + _registers.__pc = value; + return; + case UNW_REG_SP: + _registers.__r[29] = value; + return; + case UNW_MIPS_HI: + _registers.__hi = value; + return; + case UNW_MIPS_LO: + _registers.__lo = value; + return; + } + _LIBUNWIND_ABORT("unsupported mips_newabi register"); +} + +inline bool Registers_mips_newabi::validFloatRegister(int regNum) const { +#ifdef __mips_hard_float + if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) + return true; +#endif + return false; +} + +inline double Registers_mips_newabi::getFloatRegister(int regNum) const { +#ifdef __mips_hard_float + assert(validFloatRegister(regNum)); + return _floats[regNum - UNW_MIPS_F0]; +#else + _LIBUNWIND_ABORT("mips_newabi float support not implemented"); +#endif +} + +inline void Registers_mips_newabi::setFloatRegister(int regNum, + double value) { +#ifdef __mips_hard_float + assert(validFloatRegister(regNum)); + _floats[regNum - UNW_MIPS_F0] = value; +#else + _LIBUNWIND_ABORT("mips_newabi float support not implemented"); +#endif +} + +inline bool Registers_mips_newabi::validVectorRegister(int /* regNum */) const { + return false; +} + +inline v128 Registers_mips_newabi::getVectorRegister(int /* regNum */) const { + _LIBUNWIND_ABORT("mips_newabi vector support not implemented"); +} + +inline void Registers_mips_newabi::setVectorRegister(int /* regNum */, v128 /* value */) { + _LIBUNWIND_ABORT("mips_newabi vector support not implemented"); +} + +inline const char *Registers_mips_newabi::getRegisterName(int regNum) { + switch (regNum) { + case UNW_MIPS_R0: + return "$0"; + case UNW_MIPS_R1: + return "$1"; + case UNW_MIPS_R2: + return "$2"; + case UNW_MIPS_R3: + return "$3"; + case UNW_MIPS_R4: + return "$4"; + case UNW_MIPS_R5: + return "$5"; + case UNW_MIPS_R6: + return "$6"; + case UNW_MIPS_R7: + return "$7"; + case UNW_MIPS_R8: + return "$8"; + case UNW_MIPS_R9: + return "$9"; + case UNW_MIPS_R10: + return "$10"; + case UNW_MIPS_R11: + return "$11"; + case UNW_MIPS_R12: + return "$12"; + case UNW_MIPS_R13: + return "$13"; + case UNW_MIPS_R14: + return "$14"; + case UNW_MIPS_R15: + return "$15"; + case UNW_MIPS_R16: + return "$16"; + case UNW_MIPS_R17: + return "$17"; + case UNW_MIPS_R18: + return "$18"; + case UNW_MIPS_R19: + return "$19"; + case UNW_MIPS_R20: + return "$20"; + case UNW_MIPS_R21: + return "$21"; + case UNW_MIPS_R22: + return "$22"; + case UNW_MIPS_R23: + return "$23"; + case UNW_MIPS_R24: + return "$24"; + case UNW_MIPS_R25: + return "$25"; + case UNW_MIPS_R26: + return "$26"; + case UNW_MIPS_R27: + return "$27"; + case UNW_MIPS_R28: + return "$28"; + case UNW_MIPS_R29: + return "$29"; + case UNW_MIPS_R30: + return "$30"; + case UNW_MIPS_R31: + return "$31"; + case UNW_MIPS_F0: + return "$f0"; + case UNW_MIPS_F1: + return "$f1"; + case UNW_MIPS_F2: + return "$f2"; + case UNW_MIPS_F3: + return "$f3"; + case UNW_MIPS_F4: + return "$f4"; + case UNW_MIPS_F5: + return "$f5"; + case UNW_MIPS_F6: + return "$f6"; + case UNW_MIPS_F7: + return "$f7"; + case UNW_MIPS_F8: + return "$f8"; + case UNW_MIPS_F9: + return "$f9"; + case UNW_MIPS_F10: + return "$f10"; + case UNW_MIPS_F11: + return "$f11"; + case UNW_MIPS_F12: + return "$f12"; + case UNW_MIPS_F13: + return "$f13"; + case UNW_MIPS_F14: + return "$f14"; + case UNW_MIPS_F15: + return "$f15"; + case UNW_MIPS_F16: + return "$f16"; + case UNW_MIPS_F17: + return "$f17"; + case UNW_MIPS_F18: + return "$f18"; + case UNW_MIPS_F19: + return "$f19"; + case UNW_MIPS_F20: + return "$f20"; + case UNW_MIPS_F21: + return "$f21"; + case UNW_MIPS_F22: + return "$f22"; + case UNW_MIPS_F23: + return "$f23"; + case UNW_MIPS_F24: + return "$f24"; + case UNW_MIPS_F25: + return "$f25"; + case UNW_MIPS_F26: + return "$f26"; + case UNW_MIPS_F27: + return "$f27"; + case UNW_MIPS_F28: + return "$f28"; + case UNW_MIPS_F29: + return "$f29"; + case UNW_MIPS_F30: + return "$f30"; + case UNW_MIPS_F31: + return "$f31"; + case UNW_MIPS_HI: + return "$hi"; + case UNW_MIPS_LO: + return "$lo"; + default: + return "unknown register"; + } +} +#endif // _LIBUNWIND_TARGET_MIPS_NEWABI + +#if defined(_LIBUNWIND_TARGET_SPARC) +/// Registers_sparc holds the register state of a thread in a 32-bit Sparc +/// process. +class _LIBUNWIND_HIDDEN Registers_sparc { +public: + Registers_sparc(); + Registers_sparc(const void *registers); + + bool validRegister(int num) const; + uint32_t getRegister(int num) const; + void setRegister(int num, uint32_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto(); + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC; } + static int getArch() { return REGISTERS_SPARC; } + + uint64_t getSP() const { return _registers.__regs[UNW_SPARC_O6]; } + void setSP(uint32_t value) { _registers.__regs[UNW_SPARC_O6] = value; } + uint64_t getIP() const { return _registers.__regs[UNW_SPARC_O7]; } + void setIP(uint32_t value) { _registers.__regs[UNW_SPARC_O7] = value; } + +private: + struct sparc_thread_state_t { + unsigned int __regs[32]; + }; + + sparc_thread_state_t _registers; +}; + +inline Registers_sparc::Registers_sparc(const void *registers) { + static_assert((check_fit::does_fit), + "sparc registers do not fit into unw_context_t"); + memcpy(&_registers, static_cast(registers), + sizeof(_registers)); +} + +inline Registers_sparc::Registers_sparc() { + memset(&_registers, 0, sizeof(_registers)); +} + +inline bool Registers_sparc::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum < 0) + return false; + if (regNum <= UNW_SPARC_I7) + return true; + return false; +} + +inline uint32_t Registers_sparc::getRegister(int regNum) const { + if ((UNW_SPARC_G0 <= regNum) && (regNum <= UNW_SPARC_I7)) { + return _registers.__regs[regNum]; + } + + switch (regNum) { + case UNW_REG_IP: + return _registers.__regs[UNW_SPARC_O7]; + case UNW_REG_SP: + return _registers.__regs[UNW_SPARC_O6]; + } + _LIBUNWIND_ABORT("unsupported sparc register"); +} + +inline void Registers_sparc::setRegister(int regNum, uint32_t value) { + if ((UNW_SPARC_G0 <= regNum) && (regNum <= UNW_SPARC_I7)) { + _registers.__regs[regNum] = value; + return; + } + + switch (regNum) { + case UNW_REG_IP: + _registers.__regs[UNW_SPARC_O7] = value; + return; + case UNW_REG_SP: + _registers.__regs[UNW_SPARC_O6] = value; + return; + } + _LIBUNWIND_ABORT("unsupported sparc register"); +} + +inline bool Registers_sparc::validFloatRegister(int) const { return false; } + +inline double Registers_sparc::getFloatRegister(int) const { + _LIBUNWIND_ABORT("no Sparc float registers"); +} + +inline void Registers_sparc::setFloatRegister(int, double) { + _LIBUNWIND_ABORT("no Sparc float registers"); +} + +inline bool Registers_sparc::validVectorRegister(int) const { return false; } + +inline v128 Registers_sparc::getVectorRegister(int) const { + _LIBUNWIND_ABORT("no Sparc vector registers"); +} + +inline void Registers_sparc::setVectorRegister(int, v128) { + _LIBUNWIND_ABORT("no Sparc vector registers"); +} + +inline const char *Registers_sparc::getRegisterName(int regNum) { + switch (regNum) { + case UNW_REG_IP: + return "pc"; + case UNW_SPARC_G0: + return "g0"; + case UNW_SPARC_G1: + return "g1"; + case UNW_SPARC_G2: + return "g2"; + case UNW_SPARC_G3: + return "g3"; + case UNW_SPARC_G4: + return "g4"; + case UNW_SPARC_G5: + return "g5"; + case UNW_SPARC_G6: + return "g6"; + case UNW_SPARC_G7: + return "g7"; + case UNW_SPARC_O0: + return "o0"; + case UNW_SPARC_O1: + return "o1"; + case UNW_SPARC_O2: + return "o2"; + case UNW_SPARC_O3: + return "o3"; + case UNW_SPARC_O4: + return "o4"; + case UNW_SPARC_O5: + return "o5"; + case UNW_REG_SP: + case UNW_SPARC_O6: + return "sp"; + case UNW_SPARC_O7: + return "o7"; + case UNW_SPARC_L0: + return "l0"; + case UNW_SPARC_L1: + return "l1"; + case UNW_SPARC_L2: + return "l2"; + case UNW_SPARC_L3: + return "l3"; + case UNW_SPARC_L4: + return "l4"; + case UNW_SPARC_L5: + return "l5"; + case UNW_SPARC_L6: + return "l6"; + case UNW_SPARC_L7: + return "l7"; + case UNW_SPARC_I0: + return "i0"; + case UNW_SPARC_I1: + return "i1"; + case UNW_SPARC_I2: + return "i2"; + case UNW_SPARC_I3: + return "i3"; + case UNW_SPARC_I4: + return "i4"; + case UNW_SPARC_I5: + return "i5"; + case UNW_SPARC_I6: + return "fp"; + case UNW_SPARC_I7: + return "i7"; + default: + return "unknown register"; + } +} +#endif // _LIBUNWIND_TARGET_SPARC + } // namespace libunwind #endif // __REGISTERS_HPP__ diff --git a/src/Unwind-EHABI.cpp b/src/Unwind-EHABI.cpp index 5950c6902e3..f37732c6ac8 100644 --- a/src/Unwind-EHABI.cpp +++ b/src/Unwind-EHABI.cpp @@ -12,8 +12,9 @@ #include "Unwind-EHABI.h" -#if _LIBUNWIND_ARM_EHABI +#if defined(_LIBUNWIND_ARM_EHABI) +#include #include #include #include @@ -245,11 +246,9 @@ decode_eht_entry(const uint32_t* data, size_t* off, size_t* len) { return data; } -_Unwind_Reason_Code _Unwind_VRS_Interpret( - _Unwind_Context* context, - const uint32_t* data, - size_t offset, - size_t len) { +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_VRS_Interpret(_Unwind_Context *context, const uint32_t *data, + size_t offset, size_t len) { bool wrotePC = false; bool finish = false; while (offset < len && !finish) { @@ -351,6 +350,7 @@ _Unwind_Reason_Code _Unwind_VRS_Interpret( } case 0xc0: { switch (byte) { +#if defined(__ARM_WMMX) case 0xc0: case 0xc1: case 0xc2: @@ -378,6 +378,7 @@ _Unwind_Reason_Code _Unwind_VRS_Interpret( _Unwind_VRS_Pop(context, _UVRSC_WMMXC, v, _UVRSD_DOUBLE); break; } +#endif case 0xc8: case 0xc9: { uint8_t v = getByte(data, offset++); @@ -416,24 +417,21 @@ _Unwind_Reason_Code _Unwind_VRS_Interpret( return _URC_CONTINUE_UNWIND; } -extern "C" _Unwind_Reason_Code __aeabi_unwind_cpp_pr0( - _Unwind_State state, - _Unwind_Control_Block *ucbp, - _Unwind_Context *context) { +extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code +__aeabi_unwind_cpp_pr0(_Unwind_State state, _Unwind_Control_Block *ucbp, + _Unwind_Context *context) { return unwindOneFrame(state, ucbp, context); } -extern "C" _Unwind_Reason_Code __aeabi_unwind_cpp_pr1( - _Unwind_State state, - _Unwind_Control_Block *ucbp, - _Unwind_Context *context) { +extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code +__aeabi_unwind_cpp_pr1(_Unwind_State state, _Unwind_Control_Block *ucbp, + _Unwind_Context *context) { return unwindOneFrame(state, ucbp, context); } -extern "C" _Unwind_Reason_Code __aeabi_unwind_cpp_pr2( - _Unwind_State state, - _Unwind_Control_Block *ucbp, - _Unwind_Context *context) { +extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code +__aeabi_unwind_cpp_pr2(_Unwind_State state, _Unwind_Control_Block *ucbp, + _Unwind_Context *context) { return unwindOneFrame(state, ucbp, context); } @@ -454,7 +452,7 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except unw_proc_info_t frameInfo; if (unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_get_proc_info " - "failed => _URC_FATAL_PHASE1_ERROR\n", + "failed => _URC_FATAL_PHASE1_ERROR", static_cast(exception_object)); return _URC_FATAL_PHASE1_ERROR; } @@ -471,11 +469,11 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except unw_word_t pc; unw_get_reg(cursor, UNW_REG_IP, &pc); _LIBUNWIND_TRACE_UNWINDING( - "unwind_phase1(ex_ojb=%p): pc=0x%llX, start_ip=0x%llX, func=%s, " - "lsda=0x%llX, personality=0x%llX\n", - static_cast(exception_object), (long long)pc, - (long long)frameInfo.start_ip, functionName, - (long long)frameInfo.lsda, (long long)frameInfo.handler); + "unwind_phase1(ex_ojb=%p): pc=0x%" PRIxPTR ", start_ip=0x%" PRIxPTR ", func=%s, " + "lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR, + static_cast(exception_object), pc, + frameInfo.start_ip, functionName, + frameInfo.lsda, frameInfo.handler); } // If there is a personality routine, ask it if it will want to stop at @@ -484,7 +482,7 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except __personality_routine p = (__personality_routine)(long)(frameInfo.handler); _LIBUNWIND_TRACE_UNWINDING( - "unwind_phase1(ex_ojb=%p): calling personality function %p\n", + "unwind_phase1(ex_ojb=%p): calling personality function %p", static_cast(exception_object), reinterpret_cast(reinterpret_cast(p))); struct _Unwind_Context *context = (struct _Unwind_Context *)(cursor); @@ -496,7 +494,7 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except (*p)(_US_VIRTUAL_UNWIND_FRAME, exception_object, context); _LIBUNWIND_TRACE_UNWINDING( "unwind_phase1(ex_ojb=%p): personality result %d start_ip %x ehtp %p " - "additional %x\n", + "additional %x", static_cast(exception_object), personalityResult, exception_object->pr_cache.fnstart, static_cast(exception_object->pr_cache.ehtp), @@ -508,13 +506,13 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except handlerNotFound = false; // p should have initialized barrier_cache. EHABI #7.3.5 _LIBUNWIND_TRACE_UNWINDING( - "unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND \n", + "unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND", static_cast(exception_object)); return _URC_NO_REASON; case _URC_CONTINUE_UNWIND: _LIBUNWIND_TRACE_UNWINDING( - "unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", + "unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND", static_cast(exception_object)); // continue unwinding break; @@ -526,7 +524,7 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except default: // something went wrong _LIBUNWIND_TRACE_UNWINDING( - "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n", + "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR", static_cast(exception_object)); return _URC_FATAL_PHASE1_ERROR; } @@ -541,13 +539,13 @@ static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor // See comment at the start of unwind_phase1 regarding VRS integrity. unw_init_local(cursor, uc); - _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)\n", + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)", static_cast(exception_object)); int frame_count = 0; // Walk each frame until we reach where search phase said to stop. while (true) { - // Ask libuwind to get next frame (skip over first which is + // Ask libunwind to get next frame (skip over first which is // _Unwind_RaiseException or _Unwind_Resume). // // Resume only ever makes sense for 1 frame. @@ -572,7 +570,7 @@ static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor unw_get_reg(cursor, UNW_REG_SP, &sp); if (unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_get_proc_info " - "failed => _URC_FATAL_PHASE1_ERROR\n", + "failed => _URC_FATAL_PHASE2_ERROR", static_cast(exception_object)); return _URC_FATAL_PHASE2_ERROR; } @@ -587,11 +585,11 @@ static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor (frameInfo.start_ip + offset > frameInfo.end_ip)) functionName = ".anonymous."; _LIBUNWIND_TRACE_UNWINDING( - "unwind_phase2(ex_ojb=%p): start_ip=0x%llX, func=%s, sp=0x%llX, " - "lsda=0x%llX, personality=0x%llX\n", - static_cast(exception_object), (long long)frameInfo.start_ip, - functionName, (long long)sp, (long long)frameInfo.lsda, - (long long)frameInfo.handler); + "unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIxPTR ", func=%s, sp=0x%" PRIxPTR ", " + "lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR "", + static_cast(exception_object), frameInfo.start_ip, + functionName, sp, frameInfo.lsda, + frameInfo.handler); } // If there is a personality routine, tell it we are unwinding. @@ -610,7 +608,7 @@ static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor case _URC_CONTINUE_UNWIND: // Continue unwinding _LIBUNWIND_TRACE_UNWINDING( - "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", + "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND", static_cast(exception_object)); // EHABI #7.2 if (sp == exception_object->barrier_cache.sp) { @@ -621,7 +619,7 @@ static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor break; case _URC_INSTALL_CONTEXT: _LIBUNWIND_TRACE_UNWINDING( - "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT\n", + "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT", static_cast(exception_object)); // Personality routine says to transfer control to landing pad. // We may get control back if landing pad calls _Unwind_Resume(). @@ -630,9 +628,9 @@ static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor unw_get_reg(cursor, UNW_REG_IP, &pc); unw_get_reg(cursor, UNW_REG_SP, &sp); _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering " - "user code with ip=0x%llX, sp=0x%llX\n", + "user code with ip=0x%" PRIxPTR ", sp=0x%" PRIxPTR, static_cast(exception_object), - (long long)pc, (long long)sp); + pc, sp); } { @@ -668,7 +666,7 @@ static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor /// Called by __cxa_throw. Only returns if there is a fatal error. _LIBUNWIND_EXPORT _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception *exception_object) { - _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)\n", + _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)", static_cast(exception_object)); unw_context_t uc; unw_cursor_t cursor; @@ -706,7 +704,7 @@ _LIBUNWIND_EXPORT void _Unwind_Complete(_Unwind_Exception* exception_object) { /// in turn calls _Unwind_Resume_or_Rethrow(). _LIBUNWIND_EXPORT void _Unwind_Resume(_Unwind_Exception *exception_object) { - _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)\n", + _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)", static_cast(exception_object)); unw_context_t uc; unw_cursor_t cursor; @@ -730,7 +728,7 @@ _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { if (unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) result = (uintptr_t)frameInfo.lsda; _LIBUNWIND_TRACE_API( - "_Unwind_GetLanguageSpecificData(context=%p) => 0x%llx\n", + "_Unwind_GetLanguageSpecificData(context=%p) => 0x%llx", static_cast(context), (long long)result); return result; } @@ -753,12 +751,12 @@ static uint64_t ValueAsBitPattern(_Unwind_VRS_DataRepresentation representation, return value; } -_Unwind_VRS_Result +_LIBUNWIND_EXPORT _Unwind_VRS_Result _Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, uint32_t regno, _Unwind_VRS_DataRepresentation representation, void *valuep) { _LIBUNWIND_TRACE_API("_Unwind_VRS_Set(context=%p, regclass=%d, reg=%d, " - "rep=%d, value=0x%llX)\n", + "rep=%d, value=0x%llX)", static_cast(context), regclass, regno, representation, ValueAsBitPattern(representation, valuep)); @@ -771,13 +769,6 @@ _Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, *(unw_word_t *)valuep) == UNW_ESUCCESS ? _UVRSR_OK : _UVRSR_FAILED; - case _UVRSC_WMMXC: - if (representation != _UVRSD_UINT32 || regno > 3) - return _UVRSR_FAILED; - return unw_set_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno), - *(unw_word_t *)valuep) == UNW_ESUCCESS - ? _UVRSR_OK - : _UVRSR_FAILED; case _UVRSC_VFP: if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) return _UVRSR_FAILED; @@ -794,6 +785,14 @@ _Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, *(unw_fpreg_t *)valuep) == UNW_ESUCCESS ? _UVRSR_OK : _UVRSR_FAILED; +#if defined(__ARM_WMMX) + case _UVRSC_WMMXC: + if (representation != _UVRSD_UINT32 || regno > 3) + return _UVRSR_FAILED; + return unw_set_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno), + *(unw_word_t *)valuep) == UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; case _UVRSC_WMMXD: if (representation != _UVRSD_DOUBLE || regno > 31) return _UVRSR_FAILED; @@ -801,6 +800,11 @@ _Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, *(unw_fpreg_t *)valuep) == UNW_ESUCCESS ? _UVRSR_OK : _UVRSR_FAILED; +#else + case _UVRSC_WMMXC: + case _UVRSC_WMMXD: + break; +#endif } _LIBUNWIND_ABORT("unsupported register class"); } @@ -819,13 +823,6 @@ _Unwind_VRS_Get_Internal(_Unwind_Context *context, (unw_word_t *)valuep) == UNW_ESUCCESS ? _UVRSR_OK : _UVRSR_FAILED; - case _UVRSC_WMMXC: - if (representation != _UVRSD_UINT32 || regno > 3) - return _UVRSR_FAILED; - return unw_get_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno), - (unw_word_t *)valuep) == UNW_ESUCCESS - ? _UVRSR_OK - : _UVRSR_FAILED; case _UVRSC_VFP: if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) return _UVRSR_FAILED; @@ -842,6 +839,14 @@ _Unwind_VRS_Get_Internal(_Unwind_Context *context, (unw_fpreg_t *)valuep) == UNW_ESUCCESS ? _UVRSR_OK : _UVRSR_FAILED; +#if defined(__ARM_WMMX) + case _UVRSC_WMMXC: + if (representation != _UVRSD_UINT32 || regno > 3) + return _UVRSR_FAILED; + return unw_get_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno), + (unw_word_t *)valuep) == UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; case _UVRSC_WMMXD: if (representation != _UVRSD_DOUBLE || regno > 31) return _UVRSR_FAILED; @@ -849,21 +854,24 @@ _Unwind_VRS_Get_Internal(_Unwind_Context *context, (unw_fpreg_t *)valuep) == UNW_ESUCCESS ? _UVRSR_OK : _UVRSR_FAILED; +#else + case _UVRSC_WMMXC: + case _UVRSC_WMMXD: + break; +#endif } _LIBUNWIND_ABORT("unsupported register class"); } -_Unwind_VRS_Result _Unwind_VRS_Get( - _Unwind_Context *context, - _Unwind_VRS_RegClass regclass, - uint32_t regno, - _Unwind_VRS_DataRepresentation representation, - void *valuep) { +_LIBUNWIND_EXPORT _Unwind_VRS_Result +_Unwind_VRS_Get(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, + uint32_t regno, _Unwind_VRS_DataRepresentation representation, + void *valuep) { _Unwind_VRS_Result result = _Unwind_VRS_Get_Internal(context, regclass, regno, representation, valuep); _LIBUNWIND_TRACE_API("_Unwind_VRS_Get(context=%p, regclass=%d, reg=%d, " - "rep=%d, value=0x%llX, result = %d)\n", + "rep=%d, value=0x%llX, result = %d)", static_cast(context), regclass, regno, representation, ValueAsBitPattern(representation, valuep), result); @@ -875,12 +883,15 @@ _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, uint32_t discriminator, _Unwind_VRS_DataRepresentation representation) { _LIBUNWIND_TRACE_API("_Unwind_VRS_Pop(context=%p, regclass=%d, " - "discriminator=%d, representation=%d)\n", + "discriminator=%d, representation=%d)", static_cast(context), regclass, discriminator, representation); switch (regclass) { - case _UVRSC_CORE: - case _UVRSC_WMMXC: { + case _UVRSC_WMMXC: +#if !defined(__ARM_WMMX) + break; +#endif + case _UVRSC_CORE: { if (representation != _UVRSD_UINT32) return _UVRSR_FAILED; // When popping SP from the stack, we don't want to override it from the @@ -908,8 +919,11 @@ _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, } return _UVRSR_OK; } - case _UVRSC_VFP: - case _UVRSC_WMMXD: { + case _UVRSC_WMMXD: +#if !defined(__ARM_WMMX) + break; +#endif + case _UVRSC_VFP: { if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) return _UVRSR_FAILED; uint32_t first = discriminator >> 16; @@ -948,7 +962,7 @@ _Unwind_GetRegionStart(struct _Unwind_Context *context) { uintptr_t result = 0; if (unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) result = (uintptr_t)frameInfo.start_ip; - _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%llX\n", + _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%llX", static_cast(context), (long long)result); return result; } @@ -958,7 +972,7 @@ _Unwind_GetRegionStart(struct _Unwind_Context *context) { // is caught. _LIBUNWIND_EXPORT void _Unwind_DeleteException(_Unwind_Exception *exception_object) { - _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)\n", + _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)", static_cast(exception_object)); if (exception_object->exception_cleanup != NULL) (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, @@ -974,4 +988,4 @@ __gnu_unwind_frame(_Unwind_Exception *exception_object, return _URC_OK; } -#endif // _LIBUNWIND_ARM_EHABI +#endif // defined(_LIBUNWIND_ARM_EHABI) diff --git a/src/Unwind-EHABI.h b/src/Unwind-EHABI.h index a7c62df7513..fe164ff7be1 100644 --- a/src/Unwind-EHABI.h +++ b/src/Unwind-EHABI.h @@ -13,7 +13,7 @@ #include <__libunwind_config.h> -#if _LIBUNWIND_ARM_EHABI +#if defined(_LIBUNWIND_ARM_EHABI) #include #include @@ -46,6 +46,6 @@ extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr2( } // extern "C" #endif -#endif // _LIBUNWIND_ARM_EHABI +#endif // defined(_LIBUNWIND_ARM_EHABI) #endif // __UNWIND_EHABI_H__ diff --git a/src/Unwind-seh.cpp b/src/Unwind-seh.cpp new file mode 100644 index 00000000000..c5cf7c47d40 --- /dev/null +++ b/src/Unwind-seh.cpp @@ -0,0 +1,491 @@ +//===--------------------------- Unwind-seh.cpp ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implements SEH-based Itanium C++ exceptions. +// +//===----------------------------------------------------------------------===// + +#include "config.h" + +#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "libunwind_ext.h" +#include "UnwindCursor.hpp" + +using namespace libunwind; + +#define STATUS_USER_DEFINED (1u << 29) + +#define STATUS_GCC_MAGIC (('G' << 16) | ('C' << 8) | 'C') + +#define MAKE_CUSTOM_STATUS(s, c) \ + ((NTSTATUS)(((s) << 30) | STATUS_USER_DEFINED | (c))) +#define MAKE_GCC_EXCEPTION(c) \ + MAKE_CUSTOM_STATUS(STATUS_SEVERITY_SUCCESS, STATUS_GCC_MAGIC | ((c) << 24)) + +/// SEH exception raised by libunwind when the program calls +/// \c _Unwind_RaiseException. +#define STATUS_GCC_THROW MAKE_GCC_EXCEPTION(0) // 0x20474343 +/// SEH exception raised by libunwind to initiate phase 2 of exception +/// handling. +#define STATUS_GCC_UNWIND MAKE_GCC_EXCEPTION(1) // 0x21474343 + +/// Class of foreign exceptions based on unrecognized SEH exceptions. +static const uint64_t kSEHExceptionClass = 0x434C4E4753454800; // CLNGSEH\0 + +/// Exception cleanup routine used by \c _GCC_specific_handler to +/// free foreign exceptions. +static void seh_exc_cleanup(_Unwind_Reason_Code urc, _Unwind_Exception *exc) { + if (exc->exception_class != kSEHExceptionClass) + _LIBUNWIND_ABORT("SEH cleanup called on non-SEH exception"); + free(exc); +} + +static int _unw_init_seh(unw_cursor_t *cursor, CONTEXT *ctx); +static DISPATCHER_CONTEXT *_unw_seh_get_disp_ctx(unw_cursor_t *cursor); +static void _unw_seh_set_disp_ctx(unw_cursor_t *cursor, DISPATCHER_CONTEXT *disp); + +/// Common implementation of SEH-style handler functions used by Itanium- +/// style frames. Depending on how and why it was called, it may do one of: +/// a) Delegate to the given Itanium-style personality function; or +/// b) Initiate a collided unwind to halt unwinding. +_LIBUNWIND_EXPORT EXCEPTION_DISPOSITION +_GCC_specific_handler(PEXCEPTION_RECORD ms_exc, PVOID frame, PCONTEXT ms_ctx, + DISPATCHER_CONTEXT *disp, __personality_routine pers) { + unw_context_t uc; + unw_cursor_t cursor; + _Unwind_Exception *exc; + _Unwind_Action action; + struct _Unwind_Context *ctx = nullptr; + _Unwind_Reason_Code urc; + uintptr_t retval, target; + bool ours = false; + + _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler(%#010x(%x), %p)", ms_exc->ExceptionCode, ms_exc->ExceptionFlags, frame); + if (ms_exc->ExceptionCode == STATUS_GCC_UNWIND) { + if (IS_TARGET_UNWIND(ms_exc->ExceptionFlags)) { + // Set up the upper return value (the lower one and the target PC + // were set in the call to RtlUnwindEx()) for the landing pad. +#ifdef __x86_64__ + disp->ContextRecord->Rdx = ms_exc->ExceptionInformation[3]; +#elif defined(__arm__) + disp->ContextRecord->R1 = ms_exc->ExceptionInformation[3]; +#elif defined(__aarch64__) + disp->ContextRecord->X1 = ms_exc->ExceptionInformation[3]; +#endif + } + // This is the collided unwind to the landing pad. Nothing to do. + return ExceptionContinueSearch; + } + + if (ms_exc->ExceptionCode == STATUS_GCC_THROW) { + // This is (probably) a libunwind-controlled exception/unwind. Recover the + // parameters which we set below, and pass them to the personality function. + ours = true; + exc = (_Unwind_Exception *)ms_exc->ExceptionInformation[0]; + if (!IS_UNWINDING(ms_exc->ExceptionFlags) && ms_exc->NumberParameters > 1) { + ctx = (struct _Unwind_Context *)ms_exc->ExceptionInformation[1]; + action = (_Unwind_Action)ms_exc->ExceptionInformation[2]; + } + } else { + // Foreign exception. + exc = (_Unwind_Exception *)malloc(sizeof(_Unwind_Exception)); + exc->exception_class = kSEHExceptionClass; + exc->exception_cleanup = seh_exc_cleanup; + memset(exc->private_, 0, sizeof(exc->private_)); + } + if (!ctx) { + _unw_init_seh(&cursor, disp->ContextRecord); + _unw_seh_set_disp_ctx(&cursor, disp); + unw_set_reg(&cursor, UNW_REG_IP, disp->ControlPc-1); + ctx = (struct _Unwind_Context *)&cursor; + + if (!IS_UNWINDING(ms_exc->ExceptionFlags)) { + if (ours && ms_exc->NumberParameters > 1) + action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_FORCE_UNWIND); + else + action = _UA_SEARCH_PHASE; + } else { + if (ours && ms_exc->ExceptionInformation[1] == (ULONG_PTR)frame) + action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME); + else + action = _UA_CLEANUP_PHASE; + } + } + + _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler() calling personality function %p(1, %d, %llx, %p, %p)", pers, action, exc->exception_class, exc, ctx); + urc = pers(1, action, exc->exception_class, exc, ctx); + _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler() personality returned %d", urc); + switch (urc) { + case _URC_CONTINUE_UNWIND: + // If we're in phase 2, and the personality routine said to continue + // at the target frame, we're in real trouble. + if (action & _UA_HANDLER_FRAME) + _LIBUNWIND_ABORT("Personality continued unwind at the target frame!"); + return ExceptionContinueSearch; + case _URC_HANDLER_FOUND: + // If we were called by __libunwind_seh_personality(), indicate that + // a handler was found; otherwise, initiate phase 2 by unwinding. + if (ours && ms_exc->NumberParameters > 1) + return 4 /* ExecptionExecuteHandler in mingw */; + // This should never happen in phase 2. + if (IS_UNWINDING(ms_exc->ExceptionFlags)) + _LIBUNWIND_ABORT("Personality indicated exception handler in phase 2!"); + exc->private_[1] = (ULONG_PTR)frame; + if (ours) { + ms_exc->NumberParameters = 4; + ms_exc->ExceptionInformation[1] = (ULONG_PTR)frame; + } + // FIXME: Indicate target frame in foreign case! + // phase 2: the clean up phase + RtlUnwindEx(frame, (PVOID)disp->ControlPc, ms_exc, exc, ms_ctx, disp->HistoryTable); + _LIBUNWIND_ABORT("RtlUnwindEx() failed"); + case _URC_INSTALL_CONTEXT: { + // If we were called by __libunwind_seh_personality(), indicate that + // a handler was found; otherwise, it's time to initiate a collided + // unwind to the target. + if (ours && !IS_UNWINDING(ms_exc->ExceptionFlags) && ms_exc->NumberParameters > 1) + return 4 /* ExecptionExecuteHandler in mingw */; + // This should never happen in phase 1. + if (!IS_UNWINDING(ms_exc->ExceptionFlags)) + _LIBUNWIND_ABORT("Personality installed context during phase 1!"); +#ifdef __x86_64__ + exc->private_[2] = disp->TargetIp; + unw_get_reg(&cursor, UNW_X86_64_RAX, &retval); + unw_get_reg(&cursor, UNW_X86_64_RDX, &exc->private_[3]); +#elif defined(__arm__) + exc->private_[2] = disp->TargetPc; + unw_get_reg(&cursor, UNW_ARM_R0, &retval); + unw_get_reg(&cursor, UNW_ARM_R1, &exc->private_[3]); +#elif defined(__aarch64__) + exc->private_[2] = disp->TargetPc; + unw_get_reg(&cursor, UNW_ARM64_X0, &retval); + unw_get_reg(&cursor, UNW_ARM64_X1, &exc->private_[3]); +#endif + unw_get_reg(&cursor, UNW_REG_IP, &target); + ms_exc->ExceptionCode = STATUS_GCC_UNWIND; +#ifdef __x86_64__ + ms_exc->ExceptionInformation[2] = disp->TargetIp; +#elif defined(__arm__) || defined(__aarch64__) + ms_exc->ExceptionInformation[2] = disp->TargetPc; +#endif + ms_exc->ExceptionInformation[3] = exc->private_[3]; + // Give NTRTL some scratch space to keep track of the collided unwind. + // Don't use the one that was passed in; we don't want to overwrite the + // context in the DISPATCHER_CONTEXT. + CONTEXT new_ctx; + RtlUnwindEx(frame, (PVOID)target, ms_exc, (PVOID)retval, &new_ctx, disp->HistoryTable); + _LIBUNWIND_ABORT("RtlUnwindEx() failed"); + } + // Anything else indicates a serious problem. + default: return ExceptionContinueExecution; + } +} + +/// Personality function returned by \c unw_get_proc_info() in SEH contexts. +/// This is a wrapper that calls the real SEH handler function, which in +/// turn (at least, for Itanium-style frames) calls the real Itanium +/// personality function (see \c _GCC_specific_handler()). +extern "C" _Unwind_Reason_Code +__libunwind_seh_personality(int version, _Unwind_Action state, + uint64_t klass, _Unwind_Exception *exc, + struct _Unwind_Context *context) { + EXCEPTION_RECORD ms_exc; + bool phase2 = (state & (_UA_SEARCH_PHASE|_UA_CLEANUP_PHASE)) == _UA_CLEANUP_PHASE; + ms_exc.ExceptionCode = STATUS_GCC_THROW; + ms_exc.ExceptionFlags = 0; + ms_exc.NumberParameters = 3; + ms_exc.ExceptionInformation[0] = (ULONG_PTR)exc; + ms_exc.ExceptionInformation[1] = (ULONG_PTR)context; + ms_exc.ExceptionInformation[2] = state; + DISPATCHER_CONTEXT *disp_ctx = _unw_seh_get_disp_ctx((unw_cursor_t *)context); + EXCEPTION_DISPOSITION ms_act = disp_ctx->LanguageHandler(&ms_exc, + (PVOID)disp_ctx->EstablisherFrame, + disp_ctx->ContextRecord, + disp_ctx); + switch (ms_act) { + case ExceptionContinueSearch: return _URC_CONTINUE_UNWIND; + case 4 /*ExceptionExecuteHandler*/: + return phase2 ? _URC_INSTALL_CONTEXT : _URC_HANDLER_FOUND; + default: + return phase2 ? _URC_FATAL_PHASE2_ERROR : _URC_FATAL_PHASE1_ERROR; + } +} + +static _Unwind_Reason_Code +unwind_phase2_forced(unw_context_t *uc, + _Unwind_Exception *exception_object, + _Unwind_Stop_Fn stop, void *stop_parameter) { + unw_cursor_t cursor2; + unw_init_local(&cursor2, uc); + + // Walk each frame until we reach where search phase said to stop + while (unw_step(&cursor2) > 0) { + + // Update info about this frame. + unw_proc_info_t frameInfo; + if (unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): unw_step " + "failed => _URC_END_OF_STACK", + (void *)exception_object); + return _URC_FATAL_PHASE2_ERROR; + } + + // When tracing, print state information. + if (_LIBUNWIND_TRACING_UNWINDING) { + char functionBuf[512]; + const char *functionName = functionBuf; + unw_word_t offset; + if ((unw_get_proc_name(&cursor2, functionBuf, sizeof(functionBuf), + &offset) != UNW_ESUCCESS) || + (frameInfo.start_ip + offset > frameInfo.end_ip)) + functionName = ".anonymous."; + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIx64 + ", func=%s, lsda=0x%" PRIx64 ", personality=0x%" PRIx64, + (void *)exception_object, frameInfo.start_ip, functionName, + frameInfo.lsda, frameInfo.handler); + } + + // Call stop function at each frame. + _Unwind_Action action = + (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE); + _Unwind_Reason_Code stopResult = + (*stop)(1, action, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)(&cursor2), stop_parameter); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): stop function returned %d", + (void *)exception_object, stopResult); + if (stopResult != _URC_NO_REASON) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): stopped by stop function", + (void *)exception_object); + return _URC_FATAL_PHASE2_ERROR; + } + + // If there is a personality routine, tell it we are unwinding. + if (frameInfo.handler != 0) { + __personality_routine p = + (__personality_routine)(intptr_t)(frameInfo.handler); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): calling personality function %p", + (void *)exception_object, (void *)(uintptr_t)p); + _Unwind_Reason_Code personalityResult = + (*p)(1, action, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)(&cursor2)); + switch (personalityResult) { + case _URC_CONTINUE_UNWIND: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned " + "_URC_CONTINUE_UNWIND", + (void *)exception_object); + // Destructors called, continue unwinding + break; + case _URC_INSTALL_CONTEXT: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned " + "_URC_INSTALL_CONTEXT", + (void *)exception_object); + // We may get control back if landing pad calls _Unwind_Resume(). + unw_resume(&cursor2); + break; + default: + // Personality routine returned an unknown result code. + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned %d, " + "_URC_FATAL_PHASE2_ERROR", + (void *)exception_object, personalityResult); + return _URC_FATAL_PHASE2_ERROR; + } + } + } + + // Call stop function one last time and tell it we've reached the end + // of the stack. + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop " + "function with _UA_END_OF_STACK", + (void *)exception_object); + _Unwind_Action lastAction = + (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK); + (*stop)(1, lastAction, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)(&cursor2), stop_parameter); + + // Clean up phase did not resume at the frame that the search phase said it + // would. + return _URC_FATAL_PHASE2_ERROR; +} + +/// Called by \c __cxa_throw(). Only returns if there is a fatal error. +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_RaiseException(_Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)", + (void *)exception_object); + + // Mark that this is a non-forced unwind, so _Unwind_Resume() + // can do the right thing. + memset(exception_object->private_, 0, sizeof(exception_object->private_)); + + // phase 1: the search phase + // We'll let the system do that for us. + RaiseException(STATUS_GCC_THROW, 0, 1, (ULONG_PTR *)&exception_object); + + // If we get here, either something went horribly wrong or we reached the + // top of the stack. Either way, let libc++abi call std::terminate(). + return _URC_END_OF_STACK; +} + +/// When \c _Unwind_RaiseException() is in phase2, it hands control +/// to the personality function at each frame. The personality +/// may force a jump to a landing pad in that function; the landing +/// pad code may then call \c _Unwind_Resume() to continue with the +/// unwinding. Note: the call to \c _Unwind_Resume() is from compiler +/// geneated user code. All other \c _Unwind_* routines are called +/// by the C++ runtime \c __cxa_* routines. +/// +/// Note: re-throwing an exception (as opposed to continuing the unwind) +/// is implemented by having the code call \c __cxa_rethrow() which +/// in turn calls \c _Unwind_Resume_or_Rethrow(). +_LIBUNWIND_EXPORT void +_Unwind_Resume(_Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)", (void *)exception_object); + + if (exception_object->private_[0] != 0) { + unw_context_t uc; + + unw_getcontext(&uc); + unwind_phase2_forced(&uc, exception_object, + (_Unwind_Stop_Fn) exception_object->private_[0], + (void *)exception_object->private_[4]); + } else { + // Recover the parameters for the unwind from the exception object + // so we can start unwinding again. + EXCEPTION_RECORD ms_exc; + CONTEXT ms_ctx; + UNWIND_HISTORY_TABLE hist; + + memset(&ms_exc, 0, sizeof(ms_exc)); + memset(&hist, 0, sizeof(hist)); + ms_exc.ExceptionCode = STATUS_GCC_THROW; + ms_exc.ExceptionFlags = EXCEPTION_NONCONTINUABLE; + ms_exc.NumberParameters = 4; + ms_exc.ExceptionInformation[0] = (ULONG_PTR)exception_object; + ms_exc.ExceptionInformation[1] = exception_object->private_[1]; + ms_exc.ExceptionInformation[2] = exception_object->private_[2]; + ms_exc.ExceptionInformation[3] = exception_object->private_[3]; + RtlUnwindEx((PVOID)exception_object->private_[1], + (PVOID)exception_object->private_[2], &ms_exc, + exception_object, &ms_ctx, &hist); + } + + // Clients assume _Unwind_Resume() does not return, so all we can do is abort. + _LIBUNWIND_ABORT("_Unwind_Resume() can't return"); +} + +/// Not used by C++. +/// Unwinds stack, calling "stop" function at each frame. +/// Could be used to implement \c longjmp(). +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_ForcedUnwind(_Unwind_Exception *exception_object, + _Unwind_Stop_Fn stop, void *stop_parameter) { + _LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)", + (void *)exception_object, (void *)(uintptr_t)stop); + unw_context_t uc; + unw_getcontext(&uc); + + // Mark that this is a forced unwind, so _Unwind_Resume() can do + // the right thing. + exception_object->private_[0] = (uintptr_t) stop; + exception_object->private_[4] = (uintptr_t) stop_parameter; + + // do it + return unwind_phase2_forced(&uc, exception_object, stop, stop_parameter); +} + +/// Called by personality handler during phase 2 to get LSDA for current frame. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { + uintptr_t result = (uintptr_t)_unw_seh_get_disp_ctx((unw_cursor_t *)context)->HandlerData; + _LIBUNWIND_TRACE_API( + "_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR, + (void *)context, result); + return result; +} + +/// Called by personality handler during phase 2 to find the start of the +/// function. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetRegionStart(struct _Unwind_Context *context) { + DISPATCHER_CONTEXT *disp = _unw_seh_get_disp_ctx((unw_cursor_t *)context); + uintptr_t result = (uintptr_t)disp->FunctionEntry->BeginAddress + disp->ImageBase; + _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%" PRIxPTR, + (void *)context, result); + return result; +} + +static int +_unw_init_seh(unw_cursor_t *cursor, CONTEXT *context) { +#ifdef _LIBUNWIND_TARGET_X86_64 + new ((void *)cursor) UnwindCursor( + context, LocalAddressSpace::sThisAddressSpace); + auto *co = reinterpret_cast(cursor); + co->setInfoBasedOnIPRegister(); + return UNW_ESUCCESS; +#elif defined(_LIBUNWIND_TARGET_ARM) + new ((void *)cursor) UnwindCursor( + context, LocalAddressSpace::sThisAddressSpace); + auto *co = reinterpret_cast(cursor); + co->setInfoBasedOnIPRegister(); + return UNW_ESUCCESS; +#elif defined(_LIBUNWIND_TARGET_AARCH64) + new ((void *)cursor) UnwindCursor( + context, LocalAddressSpace::sThisAddressSpace); + auto *co = reinterpret_cast(cursor); + co->setInfoBasedOnIPRegister(); + return UNW_ESUCCESS; +#else + return UNW_EINVAL; +#endif +} + +static DISPATCHER_CONTEXT * +_unw_seh_get_disp_ctx(unw_cursor_t *cursor) { +#ifdef _LIBUNWIND_TARGET_X86_64 + return reinterpret_cast *>(cursor)->getDispatcherContext(); +#elif defined(_LIBUNWIND_TARGET_ARM) + return reinterpret_cast *>(cursor)->getDispatcherContext(); +#elif defined(_LIBUNWIND_TARGET_AARCH64) + return reinterpret_cast *>(cursor)->getDispatcherContext(); +#else + return nullptr; +#endif +} + +static void +_unw_seh_set_disp_ctx(unw_cursor_t *cursor, DISPATCHER_CONTEXT *disp) { +#ifdef _LIBUNWIND_TARGET_X86_64 + reinterpret_cast *>(cursor)->setDispatcherContext(disp); +#elif defined(_LIBUNWIND_TARGET_ARM) + reinterpret_cast *>(cursor)->setDispatcherContext(disp); +#elif defined(_LIBUNWIND_TARGET_AARCH64) + reinterpret_cast *>(cursor)->setDispatcherContext(disp); +#endif +} + +#endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) diff --git a/src/Unwind-sjlj.c b/src/Unwind-sjlj.c index f9256b5a926..90cac3f8c76 100644 --- a/src/Unwind-sjlj.c +++ b/src/Unwind-sjlj.c @@ -17,32 +17,26 @@ #include #include "config.h" -#include "unwind_ext.h" -// -// 32-bit iOS uses setjump/longjump based C++ exceptions. -// Other architectures use "zero cost" exceptions. -// -// With SJLJ based exceptions, any function that has a catch clause or needs to -// do any clean up when an exception propagates through it, needs to call -// _Unwind_SjLj_Register() at the start of the function and -// _Unwind_SjLj_Unregister() at the end. The register function is called with -// the address of a block of memory in the function's stack frame. The runtime -// keeps a linked list (stack) of these blocks - one per thread. The calling -// function also sets the personality and lsda fields of the block. -// +/// With SJLJ based exceptions, any function that has a catch clause or needs to +/// do any clean up when an exception propagates through it, needs to call +/// \c _Unwind_SjLj_Register at the start of the function and +/// \c _Unwind_SjLj_Unregister at the end. The register function is called with +/// the address of a block of memory in the function's stack frame. The runtime +/// keeps a linked list (stack) of these blocks - one per thread. The calling +/// function also sets the personality and lsda fields of the block. -#if _LIBUNWIND_BUILD_SJLJ_APIS +#if defined(_LIBUNWIND_BUILD_SJLJ_APIS) struct _Unwind_FunctionContext { // next function in stack of handlers struct _Unwind_FunctionContext *prev; // set by calling function before registering to be the landing pad - uintptr_t resumeLocation; + uint32_t resumeLocation; // set by personality handler to be parameters passed to landing pad function - uintptr_t resumeParameters[4]; + uint32_t resumeParameters[4]; // set by calling function before registering __personality_routine personality; // arm offset=24 @@ -53,6 +47,48 @@ struct _Unwind_FunctionContext { void *jbuf[]; }; +#if defined(_LIBUNWIND_HAS_NO_THREADS) +# define _LIBUNWIND_THREAD_LOCAL +#else +# if __STDC_VERSION__ >= 201112L +# define _LIBUNWIND_THREAD_LOCAL _Thread_local +# elif defined(_WIN32) +# define _LIBUNWIND_THREAD_LOCAL __declspec(thread) +# elif defined(__GNUC__) || defined(__clang__) +# define _LIBUNWIND_THREAD_LOCAL __thread +# else +# error Unable to create thread local storage +# endif +#endif + + +#if !defined(FOR_DYLD) + +#if defined(__APPLE__) +#include +#else +static _LIBUNWIND_THREAD_LOCAL struct _Unwind_FunctionContext *stack = NULL; +#endif + +static struct _Unwind_FunctionContext *__Unwind_SjLj_GetTopOfFunctionStack() { +#if defined(__APPLE__) + return _pthread_getspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key); +#else + return stack; +#endif +} + +static void +__Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext *fc) { +#if defined(__APPLE__) + _pthread_setspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key, fc); +#else + stack = fc; +#endif +} + +#endif + /// Called at start of each function that catches exceptions _LIBUNWIND_EXPORT void @@ -72,7 +108,7 @@ _Unwind_SjLj_Unregister(struct _Unwind_FunctionContext *fc) { static _Unwind_Reason_Code unwind_phase1(struct _Unwind_Exception *exception_object) { _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack(); - _LIBUNWIND_TRACE_UNWINDING("unwind_phase1: initial function-context=%p\n", c); + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1: initial function-context=%p", c); // walk each frame looking for a place to stop for (bool handlerNotFound = true; handlerNotFound; c = c->prev) { @@ -80,17 +116,17 @@ unwind_phase1(struct _Unwind_Exception *exception_object) { // check for no more frames if (c == NULL) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): reached " - "bottom => _URC_END_OF_STACK\n", + "bottom => _URC_END_OF_STACK", exception_object); return _URC_END_OF_STACK; } - _LIBUNWIND_TRACE_UNWINDING("unwind_phase1: function-context=%p\n", c); + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1: function-context=%p", c); // if there is a personality routine, ask it if it will want to stop at this // frame if (c->personality != NULL) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): calling " - "personality function %p\n", + "personality function %p", exception_object, c->personality); _Unwind_Reason_Code personalityResult = (*c->personality)( 1, _UA_SEARCH_PHASE, exception_object->exception_class, @@ -102,19 +138,19 @@ unwind_phase1(struct _Unwind_Exception *exception_object) { handlerNotFound = false; exception_object->private_2 = (uintptr_t) c; _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): " - "_URC_HANDLER_FOUND\n", exception_object); + "_URC_HANDLER_FOUND", exception_object); return _URC_NO_REASON; case _URC_CONTINUE_UNWIND: _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): " - "_URC_CONTINUE_UNWIND\n", exception_object); + "_URC_CONTINUE_UNWIND", exception_object); // continue unwinding break; default: // something went wrong _LIBUNWIND_TRACE_UNWINDING( - "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n", + "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR", exception_object); return _URC_FATAL_PHASE1_ERROR; } @@ -126,18 +162,18 @@ unwind_phase1(struct _Unwind_Exception *exception_object) { static _Unwind_Reason_Code unwind_phase2(struct _Unwind_Exception *exception_object) { - _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)\n", exception_object); + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)", exception_object); // walk each frame until we reach where search phase said to stop _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack(); while (true) { - _LIBUNWIND_TRACE_UNWINDING("unwind_phase2s(ex_ojb=%p): context=%p\n", + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2s(ex_ojb=%p): context=%p", exception_object, c); // check for no more frames if (c == NULL) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached " - "bottom => _URC_END_OF_STACK\n", + "bottom => _URC_END_OF_STACK", exception_object); return _URC_END_OF_STACK; } @@ -157,7 +193,7 @@ unwind_phase2(struct _Unwind_Exception *exception_object) { case _URC_CONTINUE_UNWIND: // continue unwinding _LIBUNWIND_TRACE_UNWINDING( - "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", + "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND", exception_object); if ((uintptr_t) c == exception_object->private_2) { // phase 1 said we would stop at this frame, but we did not... @@ -168,7 +204,7 @@ unwind_phase2(struct _Unwind_Exception *exception_object) { case _URC_INSTALL_CONTEXT: _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): " "_URC_INSTALL_CONTEXT, will resume at " - "landing pad %p\n", + "landing pad %p", exception_object, c->jbuf[1]); // personality routine says to transfer control to landing pad // we may get control back if landing pad calls _Unwind_Resume() @@ -202,7 +238,7 @@ unwind_phase2_forced(struct _Unwind_Exception *exception_object, // get next frame (skip over first which is _Unwind_RaiseException) if (c == NULL) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached " - "bottom => _URC_END_OF_STACK\n", + "bottom => _URC_END_OF_STACK", exception_object); return _URC_END_OF_STACK; } @@ -214,11 +250,11 @@ unwind_phase2_forced(struct _Unwind_Exception *exception_object, (*stop)(1, action, exception_object->exception_class, exception_object, (struct _Unwind_Context *)c, stop_parameter); _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " - "stop function returned %d\n", + "stop function returned %d", exception_object, stopResult); if (stopResult != _URC_NO_REASON) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " - "stopped by stop function\n", + "stopped by stop function", exception_object); return _URC_FATAL_PHASE2_ERROR; } @@ -227,7 +263,7 @@ unwind_phase2_forced(struct _Unwind_Exception *exception_object, if (c->personality != NULL) { __personality_routine p = (__personality_routine) c->personality; _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " - "calling personality function %p\n", + "calling personality function %p", exception_object, p); _Unwind_Reason_Code personalityResult = (*p)(1, action, exception_object->exception_class, exception_object, @@ -235,13 +271,13 @@ unwind_phase2_forced(struct _Unwind_Exception *exception_object, switch (personalityResult) { case _URC_CONTINUE_UNWIND: _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " - "personality returned _URC_CONTINUE_UNWIND\n", + "personality returned _URC_CONTINUE_UNWIND", exception_object); // destructors called, continue unwinding break; case _URC_INSTALL_CONTEXT: _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " - "personality returned _URC_INSTALL_CONTEXT\n", + "personality returned _URC_INSTALL_CONTEXT", exception_object); // we may get control back if landing pad calls _Unwind_Resume() __Unwind_SjLj_SetTopOfFunctionStack(c); @@ -251,7 +287,7 @@ unwind_phase2_forced(struct _Unwind_Exception *exception_object, // something went wrong _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " "personality returned %d, " - "_URC_FATAL_PHASE2_ERROR\n", + "_URC_FATAL_PHASE2_ERROR", exception_object, personalityResult); return _URC_FATAL_PHASE2_ERROR; } @@ -262,7 +298,7 @@ unwind_phase2_forced(struct _Unwind_Exception *exception_object, // call stop function one last time and tell it we've reached the end of the // stack _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop " - "function with _UA_END_OF_STACK\n", + "function with _UA_END_OF_STACK", exception_object); _Unwind_Action lastAction = (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK); @@ -278,7 +314,7 @@ unwind_phase2_forced(struct _Unwind_Exception *exception_object, /// Called by __cxa_throw. Only returns if there is a fatal error _LIBUNWIND_EXPORT _Unwind_Reason_Code _Unwind_SjLj_RaiseException(struct _Unwind_Exception *exception_object) { - _LIBUNWIND_TRACE_API("_Unwind_SjLj_RaiseException(ex_obj=%p)\n", exception_object); + _LIBUNWIND_TRACE_API("_Unwind_SjLj_RaiseException(ex_obj=%p)", exception_object); // mark that this is a non-forced unwind, so _Unwind_Resume() can do the right // thing @@ -308,7 +344,7 @@ _Unwind_SjLj_RaiseException(struct _Unwind_Exception *exception_object) { /// __cxa_rethrow() which in turn calls _Unwind_Resume_or_Rethrow() _LIBUNWIND_EXPORT void _Unwind_SjLj_Resume(struct _Unwind_Exception *exception_object) { - _LIBUNWIND_TRACE_API("_Unwind_SjLj_Resume(ex_obj=%p)\n", exception_object); + _LIBUNWIND_TRACE_API("_Unwind_SjLj_Resume(ex_obj=%p)", exception_object); if (exception_object->private_1 != 0) unwind_phase2_forced(exception_object, @@ -326,7 +362,7 @@ _Unwind_SjLj_Resume(struct _Unwind_Exception *exception_object) { _LIBUNWIND_EXPORT _Unwind_Reason_Code _Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception *exception_object) { _LIBUNWIND_TRACE_API("__Unwind_SjLj_Resume_or_Rethrow(ex_obj=%p), " - "private_1=%ld\n", + "private_1=%ld", exception_object, exception_object->private_1); // If this is non-forced and a stopping place was found, then this is a // re-throw. @@ -350,7 +386,7 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; _LIBUNWIND_TRACE_API("_Unwind_GetLanguageSpecificData(context=%p) " - "=> 0x%0lX\n", context, ufc->lsda); + "=> 0x%0lX", context, ufc->lsda); return ufc->lsda; } @@ -358,7 +394,7 @@ _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { /// Called by personality handler during phase 2 to get register values. _LIBUNWIND_EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index) { - _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d)\n", + _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d)", context, index); _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; return ufc->resumeParameters[index]; @@ -368,7 +404,7 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, /// Called by personality handler during phase 2 to alter register values. _LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index, uintptr_t new_value) { - _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0lX)\n" + _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0lX)" , context, index, new_value); _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; ufc->resumeParameters[index] = new_value; @@ -378,7 +414,7 @@ _LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index, /// Called by personality handler during phase 2 to get instruction pointer. _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) { _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; - _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%lX\n", context, + _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%lX", context, ufc->resumeLocation + 1); return ufc->resumeLocation + 1; } @@ -391,7 +427,7 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context, int *ipBefore) { _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; *ipBefore = 0; - _LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p, %p) => 0x%lX\n", + _LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p, %p) => 0x%lX", context, ipBefore, ufc->resumeLocation + 1); return ufc->resumeLocation + 1; } @@ -400,7 +436,7 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context, /// Called by personality handler during phase 2 to alter instruction pointer. _LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context, uintptr_t new_value) { - _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0lX)\n", + _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0lX)", context, new_value); _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; ufc->resumeLocation = new_value - 1; @@ -413,7 +449,7 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context *context) { // Not supported or needed for sjlj based unwinding (void)context; - _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p)\n", context); + _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p)", context); return 0; } @@ -422,7 +458,7 @@ _Unwind_GetRegionStart(struct _Unwind_Context *context) { /// is caught. _LIBUNWIND_EXPORT void _Unwind_DeleteException(struct _Unwind_Exception *exception_object) { - _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)\n", + _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)", exception_object); if (exception_object->exception_cleanup != NULL) (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, @@ -437,7 +473,7 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context *context) { // Not supported or needed for sjlj based unwinding (void)context; - _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)\n", context); + _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", context); _LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented"); } @@ -448,14 +484,14 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context *context) { // Not supported or needed for sjlj based unwinding (void)context; - _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)\n", context); + _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)", context); _LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented"); } /// Called by personality handler to get "Call Frame Area" for current frame. _LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) { - _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p)\n", context); + _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p)", context); if (context != NULL) { _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; // Setjmp/longjmp based exceptions don't have a true CFA. @@ -465,4 +501,4 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) { return 0; } -#endif // _LIBUNWIND_BUILD_SJLJ_APIS +#endif // defined(_LIBUNWIND_BUILD_SJLJ_APIS) diff --git a/src/UnwindCursor.hpp b/src/UnwindCursor.hpp index 18a780919b1..52439f9b545 100644 --- a/src/UnwindCursor.hpp +++ b/src/UnwindCursor.hpp @@ -6,7 +6,7 @@ // Source Licenses. See LICENSE.TXT for details. // // -// C++ interface to lower levels of libuwind +// C++ interface to lower levels of libunwind //===----------------------------------------------------------------------===// #ifndef __UNWINDCURSOR_HPP__ @@ -16,13 +16,53 @@ #include #include #include -#include #include +#ifdef _WIN32 + #include + #include +#endif #ifdef __APPLE__ #include #endif +#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) +// Provide a definition for the DISPATCHER_CONTEXT struct for old (Win7 and +// earlier) SDKs. +// MinGW-w64 has always provided this struct. + #if defined(_WIN32) && defined(_LIBUNWIND_TARGET_X86_64) && \ + !defined(__MINGW32__) && VER_PRODUCTBUILD < 8000 +struct _DISPATCHER_CONTEXT { + ULONG64 ControlPc; + ULONG64 ImageBase; + PRUNTIME_FUNCTION FunctionEntry; + ULONG64 EstablisherFrame; + ULONG64 TargetIp; + PCONTEXT ContextRecord; + PEXCEPTION_ROUTINE LanguageHandler; + PVOID HandlerData; + PUNWIND_HISTORY_TABLE HistoryTable; + ULONG ScopeIndex; + ULONG Fill0; +}; + #endif + +struct UNWIND_INFO { + uint8_t Version : 3; + uint8_t Flags : 5; + uint8_t SizeOfProlog; + uint8_t CountOfCodes; + uint8_t FrameRegister : 4; + uint8_t FrameOffset : 4; + uint16_t UnwindCodes[2]; +}; + +extern "C" _Unwind_Reason_Code __libunwind_seh_personality( + int, _Unwind_Action, uint64_t, _Unwind_Exception *, + struct _Unwind_Context *); + +#endif + #include "config.h" #include "AddressSpace.hpp" @@ -32,11 +72,12 @@ #include "EHHeaderParser.hpp" #include "libunwind.h" #include "Registers.hpp" +#include "RWMutex.hpp" #include "Unwind-EHABI.h" namespace libunwind { -#if _LIBUNWIND_SUPPORT_DWARF_UNWIND +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) /// Cache of recently found FDEs. template class _LIBUNWIND_HIDDEN DwarfFDECache { @@ -60,7 +101,7 @@ class _LIBUNWIND_HIDDEN DwarfFDECache { // These fields are all static to avoid needing an initializer. // There is only one instance of this class per process. - static pthread_rwlock_t _lock; + static RWMutex _lock; #ifdef __APPLE__ static void dyldUnloadHook(const struct mach_header *mh, intptr_t slide); static bool _registeredForDyldUnloads; @@ -88,7 +129,7 @@ template typename DwarfFDECache::entry DwarfFDECache::_initialBuffer[64]; template -pthread_rwlock_t DwarfFDECache::_lock = PTHREAD_RWLOCK_INITIALIZER; +RWMutex DwarfFDECache::_lock; #ifdef __APPLE__ template @@ -98,7 +139,7 @@ bool DwarfFDECache::_registeredForDyldUnloads = false; template typename A::pint_t DwarfFDECache::findFDE(pint_t mh, pint_t pc) { pint_t result = 0; - _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_rdlock(&_lock)); + _LIBUNWIND_LOG_IF_FALSE(_lock.lock_shared()); for (entry *p = _buffer; p < _bufferUsed; ++p) { if ((mh == p->mh) || (mh == 0)) { if ((p->ip_start <= pc) && (pc < p->ip_end)) { @@ -107,7 +148,7 @@ typename A::pint_t DwarfFDECache::findFDE(pint_t mh, pint_t pc) { } } } - _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock)); + _LIBUNWIND_LOG_IF_FALSE(_lock.unlock_shared()); return result; } @@ -115,7 +156,7 @@ template void DwarfFDECache::add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde) { #if !defined(_LIBUNWIND_NO_HEAP) - _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock)); + _LIBUNWIND_LOG_IF_FALSE(_lock.lock()); if (_bufferUsed >= _bufferEnd) { size_t oldSize = (size_t)(_bufferEnd - _buffer); size_t newSize = oldSize * 4; @@ -139,13 +180,13 @@ void DwarfFDECache::add(pint_t mh, pint_t ip_start, pint_t ip_end, _registeredForDyldUnloads = true; } #endif - _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock)); + _LIBUNWIND_LOG_IF_FALSE(_lock.unlock()); #endif } template void DwarfFDECache::removeAllIn(pint_t mh) { - _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock)); + _LIBUNWIND_LOG_IF_FALSE(_lock.lock()); entry *d = _buffer; for (const entry *s = _buffer; s < _bufferUsed; ++s) { if (s->mh != mh) { @@ -155,7 +196,7 @@ void DwarfFDECache::removeAllIn(pint_t mh) { } } _bufferUsed = d; - _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock)); + _LIBUNWIND_LOG_IF_FALSE(_lock.unlock()); } #ifdef __APPLE__ @@ -168,18 +209,18 @@ void DwarfFDECache::dyldUnloadHook(const struct mach_header *mh, intptr_t ) { template void DwarfFDECache::iterateCacheEntries(void (*func)( unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) { - _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock)); + _LIBUNWIND_LOG_IF_FALSE(_lock.lock()); for (entry *p = _buffer; p < _bufferUsed; ++p) { (*func)(p->ip_start, p->ip_end, p->fde, p->mh); } - _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock)); + _LIBUNWIND_LOG_IF_FALSE(_lock.unlock()); } -#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND +#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) #define arrayoffsetof(type, index, field) ((size_t)(&((type *)0)[index].field)) -#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND +#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) template class UnwindSectionHeader { public: UnwindSectionHeader(A &addressSpace, typename A::pint_t addr) @@ -367,7 +408,7 @@ template class UnwindSectionLsdaArray { A &_addressSpace; typename A::pint_t _addr; }; -#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND +#endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) class _LIBUNWIND_HIDDEN AbstractUnwindCursor { public: @@ -412,6 +453,419 @@ class _LIBUNWIND_HIDDEN AbstractUnwindCursor { #endif }; +#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32) + +/// \c UnwindCursor contains all state (including all register values) during +/// an unwind. This is normally stack-allocated inside a unw_cursor_t. +template +class UnwindCursor : public AbstractUnwindCursor { + typedef typename A::pint_t pint_t; +public: + UnwindCursor(unw_context_t *context, A &as); + UnwindCursor(CONTEXT *context, A &as); + UnwindCursor(A &as, void *threadArg); + virtual ~UnwindCursor() {} + virtual bool validReg(int); + virtual unw_word_t getReg(int); + virtual void setReg(int, unw_word_t); + virtual bool validFloatReg(int); + virtual unw_fpreg_t getFloatReg(int); + virtual void setFloatReg(int, unw_fpreg_t); + virtual int step(); + virtual void getInfo(unw_proc_info_t *); + virtual void jumpto(); + virtual bool isSignalFrame(); + virtual bool getFunctionName(char *buf, size_t len, unw_word_t *off); + virtual void setInfoBasedOnIPRegister(bool isReturnAddress = false); + virtual const char *getRegisterName(int num); +#ifdef __arm__ + virtual void saveVFPAsX(); +#endif + + DISPATCHER_CONTEXT *getDispatcherContext() { return &_dispContext; } + void setDispatcherContext(DISPATCHER_CONTEXT *disp) { _dispContext = *disp; } + +private: + + pint_t getLastPC() const { return _dispContext.ControlPc; } + void setLastPC(pint_t pc) { _dispContext.ControlPc = pc; } + RUNTIME_FUNCTION *lookUpSEHUnwindInfo(pint_t pc, pint_t *base) { + _dispContext.FunctionEntry = RtlLookupFunctionEntry(pc, + &_dispContext.ImageBase, + _dispContext.HistoryTable); + *base = _dispContext.ImageBase; + return _dispContext.FunctionEntry; + } + bool getInfoFromSEH(pint_t pc); + int stepWithSEHData() { + _dispContext.LanguageHandler = RtlVirtualUnwind(UNW_FLAG_UHANDLER, + _dispContext.ImageBase, + _dispContext.ControlPc, + _dispContext.FunctionEntry, + _dispContext.ContextRecord, + &_dispContext.HandlerData, + &_dispContext.EstablisherFrame, + NULL); + // Update some fields of the unwind info now, since we have them. + _info.lsda = reinterpret_cast(_dispContext.HandlerData); + if (_dispContext.LanguageHandler) { + _info.handler = reinterpret_cast(__libunwind_seh_personality); + } else + _info.handler = 0; + return UNW_STEP_SUCCESS; + } + + A &_addressSpace; + unw_proc_info_t _info; + DISPATCHER_CONTEXT _dispContext; + CONTEXT _msContext; + UNWIND_HISTORY_TABLE _histTable; + bool _unwindInfoMissing; +}; + + +template +UnwindCursor::UnwindCursor(unw_context_t *context, A &as) + : _addressSpace(as), _unwindInfoMissing(false) { + static_assert((check_fit, unw_cursor_t>::does_fit), + "UnwindCursor<> does not fit in unw_cursor_t"); + memset(&_info, 0, sizeof(_info)); + memset(&_histTable, 0, sizeof(_histTable)); + _dispContext.ContextRecord = &_msContext; + _dispContext.HistoryTable = &_histTable; + // Initialize MS context from ours. + R r(context); + _msContext.ContextFlags = CONTEXT_CONTROL|CONTEXT_INTEGER|CONTEXT_FLOATING_POINT; +#if defined(_LIBUNWIND_TARGET_X86_64) + _msContext.Rax = r.getRegister(UNW_X86_64_RAX); + _msContext.Rcx = r.getRegister(UNW_X86_64_RCX); + _msContext.Rdx = r.getRegister(UNW_X86_64_RDX); + _msContext.Rbx = r.getRegister(UNW_X86_64_RBX); + _msContext.Rsp = r.getRegister(UNW_X86_64_RSP); + _msContext.Rbp = r.getRegister(UNW_X86_64_RBP); + _msContext.Rsi = r.getRegister(UNW_X86_64_RSI); + _msContext.Rdi = r.getRegister(UNW_X86_64_RDI); + _msContext.R8 = r.getRegister(UNW_X86_64_R8); + _msContext.R9 = r.getRegister(UNW_X86_64_R9); + _msContext.R10 = r.getRegister(UNW_X86_64_R10); + _msContext.R11 = r.getRegister(UNW_X86_64_R11); + _msContext.R12 = r.getRegister(UNW_X86_64_R12); + _msContext.R13 = r.getRegister(UNW_X86_64_R13); + _msContext.R14 = r.getRegister(UNW_X86_64_R14); + _msContext.R15 = r.getRegister(UNW_X86_64_R15); + _msContext.Rip = r.getRegister(UNW_REG_IP); + union { + v128 v; + M128A m; + } t; + t.v = r.getVectorRegister(UNW_X86_64_XMM0); + _msContext.Xmm0 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM1); + _msContext.Xmm1 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM2); + _msContext.Xmm2 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM3); + _msContext.Xmm3 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM4); + _msContext.Xmm4 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM5); + _msContext.Xmm5 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM6); + _msContext.Xmm6 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM7); + _msContext.Xmm7 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM8); + _msContext.Xmm8 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM9); + _msContext.Xmm9 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM10); + _msContext.Xmm10 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM11); + _msContext.Xmm11 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM12); + _msContext.Xmm12 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM13); + _msContext.Xmm13 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM14); + _msContext.Xmm14 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM15); + _msContext.Xmm15 = t.m; +#elif defined(_LIBUNWIND_TARGET_ARM) + _msContext.R0 = r.getRegister(UNW_ARM_R0); + _msContext.R1 = r.getRegister(UNW_ARM_R1); + _msContext.R2 = r.getRegister(UNW_ARM_R2); + _msContext.R3 = r.getRegister(UNW_ARM_R3); + _msContext.R4 = r.getRegister(UNW_ARM_R4); + _msContext.R5 = r.getRegister(UNW_ARM_R5); + _msContext.R6 = r.getRegister(UNW_ARM_R6); + _msContext.R7 = r.getRegister(UNW_ARM_R7); + _msContext.R8 = r.getRegister(UNW_ARM_R8); + _msContext.R9 = r.getRegister(UNW_ARM_R9); + _msContext.R10 = r.getRegister(UNW_ARM_R10); + _msContext.R11 = r.getRegister(UNW_ARM_R11); + _msContext.R12 = r.getRegister(UNW_ARM_R12); + _msContext.Sp = r.getRegister(UNW_ARM_SP); + _msContext.Lr = r.getRegister(UNW_ARM_LR); + _msContext.Pc = r.getRegister(UNW_ARM_IP); + for (int i = UNW_ARM_D0; i <= UNW_ARM_D31; ++i) { + union { + uint64_t w; + double d; + } d; + d.d = r.getFloatRegister(i); + _msContext.D[i - UNW_ARM_D0] = d.w; + } +#elif defined(_LIBUNWIND_TARGET_AARCH64) + for (int i = UNW_ARM64_X0; i <= UNW_ARM64_X30; ++i) + _msContext.X[i - UNW_ARM64_X0] = r.getRegister(i); + _msContext.Sp = r.getRegister(UNW_REG_SP); + _msContext.Pc = r.getRegister(UNW_REG_IP); + for (int i = UNW_ARM64_D0; i <= UNW_ARM64_D31; ++i) + _msContext.V[i - UNW_ARM64_D0].D[0] = r.getFloatRegister(i); +#endif +} + +template +UnwindCursor::UnwindCursor(CONTEXT *context, A &as) + : _addressSpace(as), _unwindInfoMissing(false) { + static_assert((check_fit, unw_cursor_t>::does_fit), + "UnwindCursor<> does not fit in unw_cursor_t"); + memset(&_info, 0, sizeof(_info)); + memset(&_histTable, 0, sizeof(_histTable)); + _dispContext.ContextRecord = &_msContext; + _dispContext.HistoryTable = &_histTable; + _msContext = *context; +} + + +template +bool UnwindCursor::validReg(int regNum) { + if (regNum == UNW_REG_IP || regNum == UNW_REG_SP) return true; +#if defined(_LIBUNWIND_TARGET_X86_64) + if (regNum >= UNW_X86_64_RAX && regNum <= UNW_X86_64_R15) return true; +#elif defined(_LIBUNWIND_TARGET_ARM) + if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R15) return true; +#elif defined(_LIBUNWIND_TARGET_AARCH64) + if (regNum >= UNW_ARM64_X0 && regNum <= UNW_ARM64_X30) return true; +#endif + return false; +} + +template +unw_word_t UnwindCursor::getReg(int regNum) { + switch (regNum) { +#if defined(_LIBUNWIND_TARGET_X86_64) + case UNW_REG_IP: return _msContext.Rip; + case UNW_X86_64_RAX: return _msContext.Rax; + case UNW_X86_64_RDX: return _msContext.Rdx; + case UNW_X86_64_RCX: return _msContext.Rcx; + case UNW_X86_64_RBX: return _msContext.Rbx; + case UNW_REG_SP: + case UNW_X86_64_RSP: return _msContext.Rsp; + case UNW_X86_64_RBP: return _msContext.Rbp; + case UNW_X86_64_RSI: return _msContext.Rsi; + case UNW_X86_64_RDI: return _msContext.Rdi; + case UNW_X86_64_R8: return _msContext.R8; + case UNW_X86_64_R9: return _msContext.R9; + case UNW_X86_64_R10: return _msContext.R10; + case UNW_X86_64_R11: return _msContext.R11; + case UNW_X86_64_R12: return _msContext.R12; + case UNW_X86_64_R13: return _msContext.R13; + case UNW_X86_64_R14: return _msContext.R14; + case UNW_X86_64_R15: return _msContext.R15; +#elif defined(_LIBUNWIND_TARGET_ARM) + case UNW_ARM_R0: return _msContext.R0; + case UNW_ARM_R1: return _msContext.R1; + case UNW_ARM_R2: return _msContext.R2; + case UNW_ARM_R3: return _msContext.R3; + case UNW_ARM_R4: return _msContext.R4; + case UNW_ARM_R5: return _msContext.R5; + case UNW_ARM_R6: return _msContext.R6; + case UNW_ARM_R7: return _msContext.R7; + case UNW_ARM_R8: return _msContext.R8; + case UNW_ARM_R9: return _msContext.R9; + case UNW_ARM_R10: return _msContext.R10; + case UNW_ARM_R11: return _msContext.R11; + case UNW_ARM_R12: return _msContext.R12; + case UNW_REG_SP: + case UNW_ARM_SP: return _msContext.Sp; + case UNW_ARM_LR: return _msContext.Lr; + case UNW_REG_IP: + case UNW_ARM_IP: return _msContext.Pc; +#elif defined(_LIBUNWIND_TARGET_AARCH64) + case UNW_REG_SP: return _msContext.Sp; + case UNW_REG_IP: return _msContext.Pc; + default: return _msContext.X[regNum - UNW_ARM64_X0]; +#endif + } + _LIBUNWIND_ABORT("unsupported register"); +} + +template +void UnwindCursor::setReg(int regNum, unw_word_t value) { + switch (regNum) { +#if defined(_LIBUNWIND_TARGET_X86_64) + case UNW_REG_IP: _msContext.Rip = value; break; + case UNW_X86_64_RAX: _msContext.Rax = value; break; + case UNW_X86_64_RDX: _msContext.Rdx = value; break; + case UNW_X86_64_RCX: _msContext.Rcx = value; break; + case UNW_X86_64_RBX: _msContext.Rbx = value; break; + case UNW_REG_SP: + case UNW_X86_64_RSP: _msContext.Rsp = value; break; + case UNW_X86_64_RBP: _msContext.Rbp = value; break; + case UNW_X86_64_RSI: _msContext.Rsi = value; break; + case UNW_X86_64_RDI: _msContext.Rdi = value; break; + case UNW_X86_64_R8: _msContext.R8 = value; break; + case UNW_X86_64_R9: _msContext.R9 = value; break; + case UNW_X86_64_R10: _msContext.R10 = value; break; + case UNW_X86_64_R11: _msContext.R11 = value; break; + case UNW_X86_64_R12: _msContext.R12 = value; break; + case UNW_X86_64_R13: _msContext.R13 = value; break; + case UNW_X86_64_R14: _msContext.R14 = value; break; + case UNW_X86_64_R15: _msContext.R15 = value; break; +#elif defined(_LIBUNWIND_TARGET_ARM) + case UNW_ARM_R0: _msContext.R0 = value; break; + case UNW_ARM_R1: _msContext.R1 = value; break; + case UNW_ARM_R2: _msContext.R2 = value; break; + case UNW_ARM_R3: _msContext.R3 = value; break; + case UNW_ARM_R4: _msContext.R4 = value; break; + case UNW_ARM_R5: _msContext.R5 = value; break; + case UNW_ARM_R6: _msContext.R6 = value; break; + case UNW_ARM_R7: _msContext.R7 = value; break; + case UNW_ARM_R8: _msContext.R8 = value; break; + case UNW_ARM_R9: _msContext.R9 = value; break; + case UNW_ARM_R10: _msContext.R10 = value; break; + case UNW_ARM_R11: _msContext.R11 = value; break; + case UNW_ARM_R12: _msContext.R12 = value; break; + case UNW_REG_SP: + case UNW_ARM_SP: _msContext.Sp = value; break; + case UNW_ARM_LR: _msContext.Lr = value; break; + case UNW_REG_IP: + case UNW_ARM_IP: _msContext.Pc = value; break; +#elif defined(_LIBUNWIND_TARGET_AARCH64) + case UNW_REG_SP: _msContext.Sp = value; break; + case UNW_REG_IP: _msContext.Pc = value; break; + case UNW_ARM64_X0: + case UNW_ARM64_X1: + case UNW_ARM64_X2: + case UNW_ARM64_X3: + case UNW_ARM64_X4: + case UNW_ARM64_X5: + case UNW_ARM64_X6: + case UNW_ARM64_X7: + case UNW_ARM64_X8: + case UNW_ARM64_X9: + case UNW_ARM64_X10: + case UNW_ARM64_X11: + case UNW_ARM64_X12: + case UNW_ARM64_X13: + case UNW_ARM64_X14: + case UNW_ARM64_X15: + case UNW_ARM64_X16: + case UNW_ARM64_X17: + case UNW_ARM64_X18: + case UNW_ARM64_X19: + case UNW_ARM64_X20: + case UNW_ARM64_X21: + case UNW_ARM64_X22: + case UNW_ARM64_X23: + case UNW_ARM64_X24: + case UNW_ARM64_X25: + case UNW_ARM64_X26: + case UNW_ARM64_X27: + case UNW_ARM64_X28: + case UNW_ARM64_FP: + case UNW_ARM64_LR: _msContext.X[regNum - UNW_ARM64_X0] = value; break; +#endif + default: + _LIBUNWIND_ABORT("unsupported register"); + } +} + +template +bool UnwindCursor::validFloatReg(int regNum) { +#if defined(_LIBUNWIND_TARGET_ARM) + if (regNum >= UNW_ARM_S0 && regNum <= UNW_ARM_S31) return true; + if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D31) return true; +#elif defined(_LIBUNWIND_TARGET_AARCH64) + if (regNum >= UNW_ARM64_D0 && regNum <= UNW_ARM64_D31) return true; +#endif + return false; +} + +template +unw_fpreg_t UnwindCursor::getFloatReg(int regNum) { +#if defined(_LIBUNWIND_TARGET_ARM) + if (regNum >= UNW_ARM_S0 && regNum <= UNW_ARM_S31) { + union { + uint32_t w; + float f; + } d; + d.w = _msContext.S[regNum - UNW_ARM_S0]; + return d.f; + } + if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D31) { + union { + uint64_t w; + double d; + } d; + d.w = _msContext.D[regNum - UNW_ARM_D0]; + return d.d; + } + _LIBUNWIND_ABORT("unsupported float register"); +#elif defined(_LIBUNWIND_TARGET_AARCH64) + return _msContext.V[regNum - UNW_ARM64_D0].D[0]; +#else + _LIBUNWIND_ABORT("float registers unimplemented"); +#endif +} + +template +void UnwindCursor::setFloatReg(int regNum, unw_fpreg_t value) { +#if defined(_LIBUNWIND_TARGET_ARM) + if (regNum >= UNW_ARM_S0 && regNum <= UNW_ARM_S31) { + union { + uint32_t w; + float f; + } d; + d.f = value; + _msContext.S[regNum - UNW_ARM_S0] = d.w; + } + if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D31) { + union { + uint64_t w; + double d; + } d; + d.d = value; + _msContext.D[regNum - UNW_ARM_D0] = d.w; + } + _LIBUNWIND_ABORT("unsupported float register"); +#elif defined(_LIBUNWIND_TARGET_AARCH64) + _msContext.V[regNum - UNW_ARM64_D0].D[0] = value; +#else + _LIBUNWIND_ABORT("float registers unimplemented"); +#endif +} + +template void UnwindCursor::jumpto() { + RtlRestoreContext(&_msContext, nullptr); +} + +#ifdef __arm__ +template void UnwindCursor::saveVFPAsX() {} +#endif + +template +const char *UnwindCursor::getRegisterName(int regNum) { + return R::getRegisterName(regNum); +} + +template bool UnwindCursor::isSignalFrame() { + return false; +} + +#else // !defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) || !defined(_WIN32) + /// UnwindCursor contains all state (including all register values) during /// an unwind. This is normally stack allocated inside a unw_cursor_t. template @@ -440,7 +894,7 @@ class UnwindCursor : public AbstractUnwindCursor{ private: -#if _LIBUNWIND_ARM_EHABI +#if defined(_LIBUNWIND_ARM_EHABI) bool getInfoFromEHABISection(pint_t pc, const UnwindInfoSections §s); int stepWithEHABI() { @@ -458,7 +912,7 @@ class UnwindCursor : public AbstractUnwindCursor{ } #endif -#if _LIBUNWIND_SUPPORT_DWARF_UNWIND +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) bool getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections §s, uint32_t fdeSectionOffsetHint=0); int stepWithDwarfFDE() { @@ -469,11 +923,11 @@ class UnwindCursor : public AbstractUnwindCursor{ } #endif -#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND +#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) bool getInfoFromCompactEncodingSection(pint_t pc, const UnwindInfoSections §s); int stepWithCompactEncoding() { - #if _LIBUNWIND_SUPPORT_DWARF_UNWIND + #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) if ( compactSaysUseDwarf() ) return stepWithDwarfFDE(); #endif @@ -501,6 +955,13 @@ class UnwindCursor : public AbstractUnwindCursor{ } #endif +#if defined(_LIBUNWIND_TARGET_PPC64) + int stepWithCompactEncoding(Registers_ppc64 &) { + return UNW_EINVAL; + } +#endif + + #if defined(_LIBUNWIND_TARGET_AARCH64) int stepWithCompactEncoding(Registers_arm64 &) { return CompactUnwinder_arm64::stepWithCompactEncoding( @@ -508,6 +969,22 @@ class UnwindCursor : public AbstractUnwindCursor{ } #endif +#if defined(_LIBUNWIND_TARGET_MIPS_O32) + int stepWithCompactEncoding(Registers_mips_o32 &) { + return UNW_EINVAL; + } +#endif + +#if defined(_LIBUNWIND_TARGET_MIPS_NEWABI) + int stepWithCompactEncoding(Registers_mips_newabi &) { + return UNW_EINVAL; + } +#endif + +#if defined(_LIBUNWIND_TARGET_SPARC) + int stepWithCompactEncoding(Registers_sparc &) { return UNW_EINVAL; } +#endif + bool compactSaysUseDwarf(uint32_t *offset=NULL) const { R dummy; return compactSaysUseDwarf(dummy, offset); @@ -541,6 +1018,12 @@ class UnwindCursor : public AbstractUnwindCursor{ } #endif +#if defined(_LIBUNWIND_TARGET_PPC64) + bool compactSaysUseDwarf(Registers_ppc64 &, uint32_t *) const { + return true; + } +#endif + #if defined(_LIBUNWIND_TARGET_AARCH64) bool compactSaysUseDwarf(Registers_arm64 &, uint32_t *offset) const { if ((_info.format & UNWIND_ARM64_MODE_MASK) == UNWIND_ARM64_MODE_DWARF) { @@ -551,9 +1034,26 @@ class UnwindCursor : public AbstractUnwindCursor{ return false; } #endif -#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND -#if _LIBUNWIND_SUPPORT_DWARF_UNWIND +#if defined(_LIBUNWIND_TARGET_MIPS_O32) + bool compactSaysUseDwarf(Registers_mips_o32 &, uint32_t *) const { + return true; + } +#endif + +#if defined(_LIBUNWIND_TARGET_MIPS_NEWABI) + bool compactSaysUseDwarf(Registers_mips_newabi &, uint32_t *) const { + return true; + } +#endif + +#if defined(_LIBUNWIND_TARGET_SPARC) + bool compactSaysUseDwarf(Registers_sparc &, uint32_t *) const { return true; } +#endif + +#endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) + +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) compact_unwind_encoding_t dwarfEncoding() const { R dummy; return dwarfEncoding(dummy); @@ -577,18 +1077,61 @@ class UnwindCursor : public AbstractUnwindCursor{ } #endif +#if defined(_LIBUNWIND_TARGET_PPC64) + compact_unwind_encoding_t dwarfEncoding(Registers_ppc64 &) const { + return 0; + } +#endif + #if defined(_LIBUNWIND_TARGET_AARCH64) compact_unwind_encoding_t dwarfEncoding(Registers_arm64 &) const { return UNWIND_ARM64_MODE_DWARF; } #endif +#if defined(_LIBUNWIND_TARGET_ARM) + compact_unwind_encoding_t dwarfEncoding(Registers_arm &) const { + return 0; + } +#endif + #if defined (_LIBUNWIND_TARGET_OR1K) compact_unwind_encoding_t dwarfEncoding(Registers_or1k &) const { return 0; } #endif -#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND + +#if defined (_LIBUNWIND_TARGET_MIPS_O32) + compact_unwind_encoding_t dwarfEncoding(Registers_mips_o32 &) const { + return 0; + } +#endif + +#if defined (_LIBUNWIND_TARGET_MIPS_NEWABI) + compact_unwind_encoding_t dwarfEncoding(Registers_mips_newabi &) const { + return 0; + } +#endif + +#if defined(_LIBUNWIND_TARGET_SPARC) + compact_unwind_encoding_t dwarfEncoding(Registers_sparc &) const { return 0; } +#endif + +#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + +#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) + // For runtime environments using SEH unwind data without Windows runtime + // support. + pint_t getLastPC() const { /* FIXME: Implement */ return 0; } + void setLastPC(pint_t pc) { /* FIXME: Implement */ } + RUNTIME_FUNCTION *lookUpSEHUnwindInfo(pint_t pc, pint_t *base) { + /* FIXME: Implement */ + *base = 0; + return nullptr; + } + bool getInfoFromSEH(pint_t pc); + int stepWithSEHData() { /* FIXME: Implement */ return 0; } +#endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) A &_addressSpace; @@ -666,7 +1209,9 @@ template bool UnwindCursor::isSignalFrame() { return _isSignalFrame; } -#if _LIBUNWIND_ARM_EHABI +#endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) + +#if defined(_LIBUNWIND_ARM_EHABI) struct EHABIIndexEntry { uint32_t functionOffset; uint32_t data; @@ -687,7 +1232,8 @@ struct EHABISectionIterator { return _Self(addressSpace, sects, 0); } static _Self end(A& addressSpace, const UnwindInfoSections& sects) { - return _Self(addressSpace, sects, sects.arm_section_length); + return _Self(addressSpace, sects, + sects.arm_section_length / sizeof(EHABIIndexEntry)); } EHABISectionIterator(A& addressSpace, const UnwindInfoSections& sects, size_t i) @@ -737,14 +1283,21 @@ bool UnwindCursor::getInfoFromEHABISection( EHABISectionIterator::begin(_addressSpace, sects); EHABISectionIterator end = EHABISectionIterator::end(_addressSpace, sects); + if (begin == end) + return false; EHABISectionIterator itNextPC = std::upper_bound(begin, end, pc); - if (itNextPC == begin || itNextPC == end) + if (itNextPC == begin) return false; EHABISectionIterator itThisPC = itNextPC - 1; pint_t thisPC = itThisPC.functionAddress(); - pint_t nextPC = itNextPC.functionAddress(); + // If an exception is thrown from a function, corresponding to the last entry + // in the table, we don't really know the function extent and have to choose a + // value for nextPC. Choosing max() will allow the range check during trace to + // succeed. + pint_t nextPC = (itNextPC == end) ? std::numeric_limits::max() + : itNextPC.functionAddress(); pint_t indexDataAddr = itThisPC.dataAddress(); if (indexDataAddr == 0) @@ -861,7 +1414,7 @@ bool UnwindCursor::getInfoFromEHABISection( } #endif -#if _LIBUNWIND_SUPPORT_DWARF_UNWIND +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) template bool UnwindCursor::getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections §s, @@ -877,7 +1430,7 @@ bool UnwindCursor::getInfoFromDwarfSection(pint_t pc, sects.dwarf_section + fdeSectionOffsetHint, &fdeInfo, &cieInfo); } -#if _LIBUNWIND_SUPPORT_DWARF_INDEX +#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) if (!foundFDE && (sects.dwarf_index_section != 0)) { foundFDE = EHHeaderParser::findFDE( _addressSpace, pc, sects.dwarf_index_section, @@ -904,7 +1457,7 @@ bool UnwindCursor::getInfoFromDwarfSection(pint_t pc, if (foundFDE) { typename CFI_Parser::PrologInfo prolog; if (CFI_Parser::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc, - &prolog)) { + R::getArch(), &prolog)) { // Save off parsed FDE info _info.start_ip = fdeInfo.pcStart; _info.end_ip = fdeInfo.pcEnd; @@ -920,7 +1473,7 @@ bool UnwindCursor::getInfoFromDwarfSection(pint_t pc, // Add to cache (to make next lookup faster) if we had no hint // and there was no index. if (!foundInCache && (fdeSectionOffsetHint == 0)) { - #if _LIBUNWIND_SUPPORT_DWARF_INDEX + #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) if (sects.dwarf_index_section == 0) #endif DwarfFDECache::add(sects.dso_base, fdeInfo.pcStart, fdeInfo.pcEnd, @@ -929,13 +1482,13 @@ bool UnwindCursor::getInfoFromDwarfSection(pint_t pc, return true; } } - //_LIBUNWIND_DEBUG_LOG("can't find/use FDE for pc=0x%llX\n", (uint64_t)pc); + //_LIBUNWIND_DEBUG_LOG("can't find/use FDE for pc=0x%llX", (uint64_t)pc); return false; } -#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND +#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) -#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND +#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) template bool UnwindCursor::getInfoFromCompactEncodingSection(pint_t pc, const UnwindInfoSections §s) { @@ -1086,13 +1639,13 @@ bool UnwindCursor::getInfoFromCompactEncodingSection(pint_t pc, funcEnd = firstLevelNextPageFunctionOffset + sects.dso_base; if (pc < funcStart) { _LIBUNWIND_DEBUG_LOG("malformed __unwind_info, pc=0x%llX not in second " - "level compressed unwind table. funcStart=0x%llX\n", + "level compressed unwind table. funcStart=0x%llX", (uint64_t) pc, (uint64_t) funcStart); return false; } if (pc > funcEnd) { _LIBUNWIND_DEBUG_LOG("malformed __unwind_info, pc=0x%llX not in second " - "level compressed unwind table. funcEnd=0x%llX\n", + "level compressed unwind table. funcEnd=0x%llX", (uint64_t) pc, (uint64_t) funcEnd); return false; } @@ -1113,7 +1666,7 @@ bool UnwindCursor::getInfoFromCompactEncodingSection(pint_t pc, } } else { _LIBUNWIND_DEBUG_LOG("malformed __unwind_info at 0x%0llX bad second " - "level page\n", + "level page", (uint64_t) sects.compact_unwind_section); return false; } @@ -1143,7 +1696,7 @@ bool UnwindCursor::getInfoFromCompactEncodingSection(pint_t pc, } if (lsda == 0) { _LIBUNWIND_DEBUG_LOG("found encoding 0x%08X with HAS_LSDA bit set for " - "pc=0x%0llX, but lsda table has no entry\n", + "pc=0x%0llX, but lsda table has no entry", encoding, (uint64_t) pc); return false; } @@ -1156,7 +1709,7 @@ bool UnwindCursor::getInfoFromCompactEncodingSection(pint_t pc, --personalityIndex; // change 1-based to zero-based index if (personalityIndex > sectionHeader.personalityArrayCount()) { _LIBUNWIND_DEBUG_LOG("found encoding 0x%08X with personality index %d, " - "but personality table has only %d entires\n", + "but personality table has only %d entires", encoding, personalityIndex, sectionHeader.personalityArrayCount()); return false; @@ -1189,13 +1742,62 @@ bool UnwindCursor::getInfoFromCompactEncodingSection(pint_t pc, _info.extra = sects.dso_base; return true; } -#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND +#endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) + + +#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) +template +bool UnwindCursor::getInfoFromSEH(pint_t pc) { + pint_t base; + RUNTIME_FUNCTION *unwindEntry = lookUpSEHUnwindInfo(pc, &base); + if (!unwindEntry) { + _LIBUNWIND_DEBUG_LOG("\tpc not in table, pc=0x%llX", (uint64_t) pc); + return false; + } + _info.gp = 0; + _info.flags = 0; + _info.format = 0; + _info.unwind_info_size = sizeof(RUNTIME_FUNCTION); + _info.unwind_info = reinterpret_cast(unwindEntry); + _info.extra = base; + _info.start_ip = base + unwindEntry->BeginAddress; +#ifdef _LIBUNWIND_TARGET_X86_64 + _info.end_ip = base + unwindEntry->EndAddress; + // Only fill in the handler and LSDA if they're stale. + if (pc != getLastPC()) { + UNWIND_INFO *xdata = reinterpret_cast(base + unwindEntry->UnwindData); + if (xdata->Flags & (UNW_FLAG_EHANDLER|UNW_FLAG_UHANDLER)) { + // The personality is given in the UNWIND_INFO itself. The LSDA immediately + // follows the UNWIND_INFO. (This follows how both Clang and MSVC emit + // these structures.) + // N.B. UNWIND_INFO structs are DWORD-aligned. + uint32_t lastcode = (xdata->CountOfCodes + 1) & ~1; + const uint32_t *handler = reinterpret_cast(&xdata->UnwindCodes[lastcode]); + _info.lsda = reinterpret_cast(handler+1); + if (*handler) { + _info.handler = reinterpret_cast(__libunwind_seh_personality); + } else + _info.handler = 0; + } else { + _info.lsda = 0; + _info.handler = 0; + } + } +#elif defined(_LIBUNWIND_TARGET_ARM) + _info.end_ip = _info.start_ip + unwindEntry->FunctionLength; + _info.lsda = 0; // FIXME + _info.handler = 0; // FIXME +#endif + setLastPC(pc); + return true; +} +#endif template void UnwindCursor::setInfoBasedOnIPRegister(bool isReturnAddress) { pint_t pc = (pint_t)this->getReg(UNW_REG_IP); -#if _LIBUNWIND_ARM_EHABI +#if defined(_LIBUNWIND_ARM_EHABI) // Remove the thumb bit so the IP represents the actual instruction address. // This matches the behaviour of _Unwind_GetIP on arm. pc &= (pint_t)~0x1; @@ -1212,11 +1814,11 @@ void UnwindCursor::setInfoBasedOnIPRegister(bool isReturnAddress) { // Ask address space object to find unwind sections for this pc. UnwindInfoSections sects; if (_addressSpace.findUnwindSections(pc, sects)) { -#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND +#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) // If there is a compact unwind encoding table, look there first. if (sects.compact_unwind_section != 0) { if (this->getInfoFromCompactEncodingSection(pc, sects)) { - #if _LIBUNWIND_SUPPORT_DWARF_UNWIND + #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) // Found info in table, done unless encoding says to use dwarf. uint32_t dwarfOffset; if ((sects.dwarf_section != 0) && compactSaysUseDwarf(&dwarfOffset)) { @@ -1233,9 +1835,15 @@ void UnwindCursor::setInfoBasedOnIPRegister(bool isReturnAddress) { return; } } -#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND +#endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) -#if _LIBUNWIND_SUPPORT_DWARF_UNWIND +#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) + // If there is SEH unwind info, look there next. + if (this->getInfoFromSEH(pc)) + return; +#endif + +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) // If there is dwarf unwind info, look there next. if (sects.dwarf_section != 0) { if (this->getInfoFromDwarfSection(pc, sects)) { @@ -1245,14 +1853,14 @@ void UnwindCursor::setInfoBasedOnIPRegister(bool isReturnAddress) { } #endif -#if _LIBUNWIND_ARM_EHABI +#if defined(_LIBUNWIND_ARM_EHABI) // If there is ARM EHABI unwind info, look there next. if (sects.arm_section != 0 && this->getInfoFromEHABISection(pc, sects)) return; #endif } -#if _LIBUNWIND_SUPPORT_DWARF_UNWIND +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) // There is no static unwind info for this pc. Look to see if an FDE was // dynamically registered for it. pint_t cachedFDE = DwarfFDECache::findFDE(0, pc); @@ -1264,7 +1872,7 @@ void UnwindCursor::setInfoBasedOnIPRegister(bool isReturnAddress) { if (msg == NULL) { typename CFI_Parser::PrologInfo prolog; if (CFI_Parser::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, - pc, &prolog)) { + pc, R::getArch(), &prolog)) { // save off parsed FDE info _info.start_ip = fdeInfo.pcStart; _info.end_ip = fdeInfo.pcEnd; @@ -1293,8 +1901,8 @@ void UnwindCursor::setInfoBasedOnIPRegister(bool isReturnAddress) { // Double check this FDE is for a function that includes the pc. if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd)) { typename CFI_Parser::PrologInfo prolog; - if (CFI_Parser::parseFDEInstructions(_addressSpace, fdeInfo, - cieInfo, pc, &prolog)) { + if (CFI_Parser::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, + pc, R::getArch(), &prolog)) { // save off parsed FDE info _info.start_ip = fdeInfo.pcStart; _info.end_ip = fdeInfo.pcEnd; @@ -1311,7 +1919,7 @@ void UnwindCursor::setInfoBasedOnIPRegister(bool isReturnAddress) { } } } -#endif // #if _LIBUNWIND_SUPPORT_DWARF_UNWIND +#endif // #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) // no unwind info, flag that we can't reliably unwind _unwindInfoMissing = true; @@ -1325,14 +1933,17 @@ int UnwindCursor::step() { // Use unwinding info to modify register set as if function returned. int result; -#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND +#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) result = this->stepWithCompactEncoding(); -#elif _LIBUNWIND_SUPPORT_DWARF_UNWIND +#elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) + result = this->stepWithSEHData(); +#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) result = this->stepWithDwarfFDE(); -#elif _LIBUNWIND_ARM_EHABI +#elif defined(_LIBUNWIND_ARM_EHABI) result = this->stepWithEHABI(); #else #error Need _LIBUNWIND_SUPPORT_COMPACT_UNWIND or \ + _LIBUNWIND_SUPPORT_SEH_UNWIND or \ _LIBUNWIND_SUPPORT_DWARF_UNWIND or \ _LIBUNWIND_ARM_EHABI #endif @@ -1342,8 +1953,6 @@ int UnwindCursor::step() { this->setInfoBasedOnIPRegister(true); if (_unwindInfoMissing) return UNW_STEP_END; - if (_info.gp) - setReg(UNW_REG_SP, getReg(UNW_REG_SP) + _info.gp); } return result; diff --git a/src/UnwindLevel1-gcc-ext.c b/src/UnwindLevel1-gcc-ext.c index 28ba0928121..1c662658546 100644 --- a/src/UnwindLevel1-gcc-ext.c +++ b/src/UnwindLevel1-gcc-ext.c @@ -23,22 +23,26 @@ #include "Unwind-EHABI.h" #include "unwind.h" -#if _LIBUNWIND_BUILD_ZERO_COST_APIS +#if defined(_LIBUNWIND_BUILD_ZERO_COST_APIS) + +#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) +#define private_1 private_[0] +#endif /// Called by __cxa_rethrow(). _LIBUNWIND_EXPORT _Unwind_Reason_Code _Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object) { -#if _LIBUNWIND_ARM_EHABI - _LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%ld\n", +#if defined(_LIBUNWIND_ARM_EHABI) + _LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%ld", (void *)exception_object, (long)exception_object->unwinder_cache.reserved1); #else - _LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%ld\n", + _LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%" PRIdPTR, (void *)exception_object, - (long)exception_object->private_1); + (intptr_t)exception_object->private_1); #endif -#if _LIBUNWIND_ARM_EHABI +#if defined(_LIBUNWIND_ARM_EHABI) // _Unwind_RaiseException on EHABI will always set the reserved1 field to 0, // which is in the same position as private_1 below. return _Unwind_RaiseException(exception_object); @@ -66,7 +70,7 @@ _Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object) { _LIBUNWIND_EXPORT uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context *context) { (void)context; - _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)\n", (void *)context); + _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", (void *)context); _LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented"); } @@ -76,7 +80,7 @@ _Unwind_GetDataRelBase(struct _Unwind_Context *context) { _LIBUNWIND_EXPORT uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context *context) { (void)context; - _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)\n", (void *)context); + _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)", (void *)context); _LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented"); } @@ -84,7 +88,7 @@ _Unwind_GetTextRelBase(struct _Unwind_Context *context) { /// Scans unwind information to find the function that contains the /// specified code address "pc". _LIBUNWIND_EXPORT void *_Unwind_FindEnclosingFunction(void *pc) { - _LIBUNWIND_TRACE_API("_Unwind_FindEnclosingFunction(pc=%p)\n", pc); + _LIBUNWIND_TRACE_API("_Unwind_FindEnclosingFunction(pc=%p)", pc); // This is slow, but works. // We create an unwind cursor then alter the IP to be pc unw_cursor_t cursor; @@ -92,9 +96,9 @@ _LIBUNWIND_EXPORT void *_Unwind_FindEnclosingFunction(void *pc) { unw_proc_info_t info; unw_getcontext(&uc); unw_init_local(&cursor, &uc); - unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(long) pc); + unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(intptr_t) pc); if (unw_get_proc_info(&cursor, &info) == UNW_ESUCCESS) - return (void *)(long) info.start_ip; + return (void *)(intptr_t) info.start_ip; else return NULL; } @@ -108,10 +112,10 @@ _Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) { unw_getcontext(&uc); unw_init_local(&cursor, &uc); - _LIBUNWIND_TRACE_API("_Unwind_Backtrace(callback=%p)\n", + _LIBUNWIND_TRACE_API("_Unwind_Backtrace(callback=%p)", (void *)(uintptr_t)callback); -#if _LIBUNWIND_ARM_EHABI +#if defined(_LIBUNWIND_ARM_EHABI) // Create a mock exception object for force unwinding. _Unwind_Exception ex; memset(&ex, '\0', sizeof(ex)); @@ -122,12 +126,12 @@ _Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) { while (true) { _Unwind_Reason_Code result; -#if !_LIBUNWIND_ARM_EHABI - // ask libuwind to get next frame (skip over first frame which is +#if !defined(_LIBUNWIND_ARM_EHABI) + // ask libunwind to get next frame (skip over first frame which is // _Unwind_Backtrace()) if (unw_step(&cursor) <= 0) { _LIBUNWIND_TRACE_UNWINDING(" _backtrace: ended because cursor reached " - "bottom of stack, returning %d\n", + "bottom of stack, returning %d", _URC_END_OF_STACK); return _URC_END_OF_STACK; } @@ -154,7 +158,7 @@ _Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) { _URC_CONTINUE_UNWIND) { return _URC_END_OF_STACK; } -#endif // _LIBUNWIND_ARM_EHABI +#endif // defined(_LIBUNWIND_ARM_EHABI) // debugging if (_LIBUNWIND_TRACING_UNWINDING) { @@ -164,8 +168,8 @@ _Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) { unw_get_proc_name(&cursor, functionName, 512, &offset); unw_get_proc_info(&cursor, &frame); _LIBUNWIND_TRACE_UNWINDING( - " _backtrace: start_ip=0x%llX, func=%s, lsda=0x%llX, context=%p\n", - (long long)frame.start_ip, functionName, (long long)frame.lsda, + " _backtrace: start_ip=0x%" PRIxPTR ", func=%s, lsda=0x%" PRIxPTR ", context=%p", + frame.start_ip, functionName, frame.lsda, (void *)&cursor); } @@ -173,14 +177,14 @@ _Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) { result = (*callback)((struct _Unwind_Context *)(&cursor), ref); if (result != _URC_NO_REASON) { _LIBUNWIND_TRACE_UNWINDING( - " _backtrace: ended because callback returned %d\n", result); + " _backtrace: ended because callback returned %d", result); return result; } } } -/// Find dwarf unwind info for an address 'pc' in some function. +/// Find DWARF unwind info for an address 'pc' in some function. _LIBUNWIND_EXPORT const void *_Unwind_Find_FDE(const void *pc, struct dwarf_eh_bases *bases) { // This is slow, but works. @@ -190,14 +194,14 @@ _LIBUNWIND_EXPORT const void *_Unwind_Find_FDE(const void *pc, unw_proc_info_t info; unw_getcontext(&uc); unw_init_local(&cursor, &uc); - unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(long) pc); + unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(intptr_t) pc); unw_get_proc_info(&cursor, &info); bases->tbase = (uintptr_t)info.extra; bases->dbase = 0; // dbase not used on Mac OS X bases->func = (uintptr_t)info.start_ip; - _LIBUNWIND_TRACE_API("_Unwind_Find_FDE(pc=%p) => %p\n", pc, - (void *)(long) info.unwind_info); - return (void *)(long) info.unwind_info; + _LIBUNWIND_TRACE_API("_Unwind_Find_FDE(pc=%p) => %p", pc, + (void *)(intptr_t) info.unwind_info); + return (void *)(intptr_t) info.unwind_info; } /// Returns the CFA (call frame area, or stack pointer at start of function) @@ -206,8 +210,8 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) { unw_cursor_t *cursor = (unw_cursor_t *)context; unw_word_t result; unw_get_reg(cursor, UNW_REG_SP, &result); - _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p) => 0x%" PRIx64 "\n", - (void *)context, (uint64_t)result); + _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p) => 0x%" PRIxPTR, + (void *)context, result); return (uintptr_t)result; } @@ -217,19 +221,19 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) { /// site address. Normally IP is the return address. _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context, int *ipBefore) { - _LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p)\n", (void *)context); + _LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p)", (void *)context); *ipBefore = 0; return _Unwind_GetIP(context); } -#if _LIBUNWIND_SUPPORT_DWARF_UNWIND +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) /// Called by programs with dynamic code generators that want /// to register a dynamically generated FDE. /// This function has existed on Mac OS X since 10.4, but /// was broken until 10.6. _LIBUNWIND_EXPORT void __register_frame(const void *fde) { - _LIBUNWIND_TRACE_API("__register_frame(%p)\n", fde); + _LIBUNWIND_TRACE_API("__register_frame(%p)", fde); _unw_add_dynamic_fde((unw_word_t)(uintptr_t) fde); } @@ -239,7 +243,7 @@ _LIBUNWIND_EXPORT void __register_frame(const void *fde) { /// This function has existed on Mac OS X since 10.4, but /// was broken until 10.6. _LIBUNWIND_EXPORT void __deregister_frame(const void *fde) { - _LIBUNWIND_TRACE_API("__deregister_frame(%p)\n", fde); + _LIBUNWIND_TRACE_API("__deregister_frame(%p)", fde); _unw_remove_dynamic_fde((unw_word_t)(uintptr_t) fde); } @@ -252,14 +256,14 @@ _LIBUNWIND_EXPORT void __deregister_frame(const void *fde) { // applications working. We also add the not in 10.6 symbol so that nwe // application won't be able to use them. -#if _LIBUNWIND_SUPPORT_FRAME_APIS +#if defined(_LIBUNWIND_SUPPORT_FRAME_APIS) _LIBUNWIND_EXPORT void __register_frame_info_bases(const void *fde, void *ob, void *tb, void *db) { (void)fde; (void)ob; (void)tb; (void)db; - _LIBUNWIND_TRACE_API("__register_frame_info_bases(%p,%p, %p, %p)\n", + _LIBUNWIND_TRACE_API("__register_frame_info_bases(%p,%p, %p, %p)", fde, ob, tb, db); // do nothing, this function never worked in Mac OS X } @@ -267,7 +271,7 @@ _LIBUNWIND_EXPORT void __register_frame_info_bases(const void *fde, void *ob, _LIBUNWIND_EXPORT void __register_frame_info(const void *fde, void *ob) { (void)fde; (void)ob; - _LIBUNWIND_TRACE_API("__register_frame_info(%p, %p)\n", fde, ob); + _LIBUNWIND_TRACE_API("__register_frame_info(%p, %p)", fde, ob); // do nothing, this function never worked in Mac OS X } @@ -279,38 +283,38 @@ _LIBUNWIND_EXPORT void __register_frame_info_table_bases(const void *fde, (void)tb; (void)db; _LIBUNWIND_TRACE_API("__register_frame_info_table_bases" - "(%p,%p, %p, %p)\n", fde, ob, tb, db); + "(%p,%p, %p, %p)", fde, ob, tb, db); // do nothing, this function never worked in Mac OS X } _LIBUNWIND_EXPORT void __register_frame_info_table(const void *fde, void *ob) { (void)fde; (void)ob; - _LIBUNWIND_TRACE_API("__register_frame_info_table(%p, %p)\n", fde, ob); + _LIBUNWIND_TRACE_API("__register_frame_info_table(%p, %p)", fde, ob); // do nothing, this function never worked in Mac OS X } _LIBUNWIND_EXPORT void __register_frame_table(const void *fde) { (void)fde; - _LIBUNWIND_TRACE_API("__register_frame_table(%p)\n", fde); + _LIBUNWIND_TRACE_API("__register_frame_table(%p)", fde); // do nothing, this function never worked in Mac OS X } _LIBUNWIND_EXPORT void *__deregister_frame_info(const void *fde) { (void)fde; - _LIBUNWIND_TRACE_API("__deregister_frame_info(%p)\n", fde); + _LIBUNWIND_TRACE_API("__deregister_frame_info(%p)", fde); // do nothing, this function never worked in Mac OS X return NULL; } _LIBUNWIND_EXPORT void *__deregister_frame_info_bases(const void *fde) { (void)fde; - _LIBUNWIND_TRACE_API("__deregister_frame_info_bases(%p)\n", fde); + _LIBUNWIND_TRACE_API("__deregister_frame_info_bases(%p)", fde); // do nothing, this function never worked in Mac OS X return NULL; } -#endif // _LIBUNWIND_SUPPORT_FRAME_APIS +#endif // defined(_LIBUNWIND_SUPPORT_FRAME_APIS) -#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND +#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) -#endif // _LIBUNWIND_BUILD_ZERO_COST_APIS +#endif // defined(_LIBUNWIND_BUILD_ZERO_COST_APIS) diff --git a/src/UnwindLevel1.c b/src/UnwindLevel1.c index 7294f255407..0a04438bba2 100644 --- a/src/UnwindLevel1.c +++ b/src/UnwindLevel1.c @@ -30,7 +30,9 @@ #include "unwind.h" #include "config.h" -#if !_LIBUNWIND_ARM_EHABI +#if !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__) + +#ifndef _LIBUNWIND_SUPPORT_SEH_UNWIND static _Unwind_Reason_Code unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) { @@ -39,17 +41,17 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except // Walk each frame looking for a place to stop. bool handlerNotFound = true; while (handlerNotFound) { - // Ask libuwind to get next frame (skip over first which is + // Ask libunwind to get next frame (skip over first which is // _Unwind_RaiseException). int stepResult = unw_step(cursor); if (stepResult == 0) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step() reached " - "bottom => _URC_END_OF_STACK\n", + "bottom => _URC_END_OF_STACK", (void *)exception_object); return _URC_END_OF_STACK; } else if (stepResult < 0) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step failed => " - "_URC_FATAL_PHASE1_ERROR\n", + "_URC_FATAL_PHASE1_ERROR", (void *)exception_object); return _URC_FATAL_PHASE1_ERROR; } @@ -59,7 +61,7 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except unw_word_t sp; if (unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_get_proc_info " - "failed => _URC_FATAL_PHASE1_ERROR\n", + "failed => _URC_FATAL_PHASE1_ERROR", (void *)exception_object); return _URC_FATAL_PHASE1_ERROR; } @@ -76,8 +78,8 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except unw_word_t pc; unw_get_reg(cursor, UNW_REG_IP, &pc); _LIBUNWIND_TRACE_UNWINDING( - "unwind_phase1(ex_ojb=%p): pc=0x%" PRIx64 ", start_ip=0x%" PRIx64 - ", func=%s, lsda=0x%" PRIx64 ", personality=0x%" PRIx64 "\n", + "unwind_phase1(ex_ojb=%p): pc=0x%" PRIxPTR ", start_ip=0x%" PRIxPTR + ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR "", (void *)exception_object, pc, frameInfo.start_ip, functionName, frameInfo.lsda, frameInfo.handler); } @@ -86,9 +88,9 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except // this frame. if (frameInfo.handler != 0) { __personality_routine p = - (__personality_routine)(long)(frameInfo.handler); + (__personality_routine)(uintptr_t)(frameInfo.handler); _LIBUNWIND_TRACE_UNWINDING( - "unwind_phase1(ex_ojb=%p): calling personality function %p\n", + "unwind_phase1(ex_ojb=%p): calling personality function %p", (void *)exception_object, (void *)(uintptr_t)p); _Unwind_Reason_Code personalityResult = (*p)(1, _UA_SEARCH_PHASE, exception_object->exception_class, @@ -101,13 +103,13 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except unw_get_reg(cursor, UNW_REG_SP, &sp); exception_object->private_2 = (uintptr_t)sp; _LIBUNWIND_TRACE_UNWINDING( - "unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND \n", + "unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND", (void *)exception_object); return _URC_NO_REASON; case _URC_CONTINUE_UNWIND: _LIBUNWIND_TRACE_UNWINDING( - "unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", + "unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND", (void *)exception_object); // continue unwinding break; @@ -115,7 +117,7 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except default: // something went wrong _LIBUNWIND_TRACE_UNWINDING( - "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n", + "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR", (void *)exception_object); return _URC_FATAL_PHASE1_ERROR; } @@ -129,23 +131,23 @@ static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) { unw_init_local(cursor, uc); - _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)\n", + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)", (void *)exception_object); // Walk each frame until we reach where search phase said to stop. while (true) { - // Ask libuwind to get next frame (skip over first which is + // Ask libunwind to get next frame (skip over first which is // _Unwind_RaiseException). int stepResult = unw_step(cursor); if (stepResult == 0) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached " - "bottom => _URC_END_OF_STACK\n", + "bottom => _URC_END_OF_STACK", (void *)exception_object); return _URC_END_OF_STACK; } else if (stepResult < 0) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step failed => " - "_URC_FATAL_PHASE1_ERROR\n", + "_URC_FATAL_PHASE1_ERROR", (void *)exception_object); return _URC_FATAL_PHASE2_ERROR; } @@ -156,7 +158,7 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except unw_get_reg(cursor, UNW_REG_SP, &sp); if (unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_get_proc_info " - "failed => _URC_FATAL_PHASE1_ERROR\n", + "failed => _URC_FATAL_PHASE1_ERROR", (void *)exception_object); return _URC_FATAL_PHASE2_ERROR; } @@ -170,9 +172,9 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except &offset) != UNW_ESUCCESS) || (frameInfo.start_ip + offset > frameInfo.end_ip)) functionName = ".anonymous."; - _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIx64 - ", func=%s, sp=0x%" PRIx64 ", lsda=0x%" PRIx64 - ", personality=0x%" PRIx64 "\n", + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIxPTR + ", func=%s, sp=0x%" PRIxPTR ", lsda=0x%" PRIxPTR + ", personality=0x%" PRIxPTR, (void *)exception_object, frameInfo.start_ip, functionName, sp, frameInfo.lsda, frameInfo.handler); @@ -181,7 +183,7 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except // If there is a personality routine, tell it we are unwinding. if (frameInfo.handler != 0) { __personality_routine p = - (__personality_routine)(long)(frameInfo.handler); + (__personality_routine)(uintptr_t)(frameInfo.handler); _Unwind_Action action = _UA_CLEANUP_PHASE; if (sp == exception_object->private_2) { // Tell personality this was the frame it marked in phase 1. @@ -194,7 +196,7 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except case _URC_CONTINUE_UNWIND: // Continue unwinding _LIBUNWIND_TRACE_UNWINDING( - "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", + "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND", (void *)exception_object); if (sp == exception_object->private_2) { // Phase 1 said we would stop at this frame, but we did not... @@ -204,7 +206,7 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except break; case _URC_INSTALL_CONTEXT: _LIBUNWIND_TRACE_UNWINDING( - "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT\n", + "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT", (void *)exception_object); // Personality routine says to transfer control to landing pad. // We may get control back if landing pad calls _Unwind_Resume(). @@ -213,8 +215,8 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except unw_get_reg(cursor, UNW_REG_IP, &pc); unw_get_reg(cursor, UNW_REG_SP, &sp); _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering " - "user code with ip=0x%" PRIx64 - ", sp=0x%" PRIx64 "\n", + "user code with ip=0x%" PRIxPTR + ", sp=0x%" PRIxPTR, (void *)exception_object, pc, sp); } unw_resume(cursor); @@ -247,7 +249,7 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor, unw_proc_info_t frameInfo; if (unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): unw_step " - "failed => _URC_END_OF_STACK\n", + "failed => _URC_END_OF_STACK", (void *)exception_object); return _URC_FATAL_PHASE2_ERROR; } @@ -262,8 +264,8 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor, (frameInfo.start_ip + offset > frameInfo.end_ip)) functionName = ".anonymous."; _LIBUNWIND_TRACE_UNWINDING( - "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIx64 - ", func=%s, lsda=0x%" PRIx64 ", personality=0x%" PRIx64 "\n", + "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIxPTR + ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR, (void *)exception_object, frameInfo.start_ip, functionName, frameInfo.lsda, frameInfo.handler); } @@ -275,11 +277,11 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor, (*stop)(1, action, exception_object->exception_class, exception_object, (struct _Unwind_Context *)(cursor), stop_parameter); _LIBUNWIND_TRACE_UNWINDING( - "unwind_phase2_forced(ex_ojb=%p): stop function returned %d\n", + "unwind_phase2_forced(ex_ojb=%p): stop function returned %d", (void *)exception_object, stopResult); if (stopResult != _URC_NO_REASON) { _LIBUNWIND_TRACE_UNWINDING( - "unwind_phase2_forced(ex_ojb=%p): stopped by stop function\n", + "unwind_phase2_forced(ex_ojb=%p): stopped by stop function", (void *)exception_object); return _URC_FATAL_PHASE2_ERROR; } @@ -287,9 +289,9 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor, // If there is a personality routine, tell it we are unwinding. if (frameInfo.handler != 0) { __personality_routine p = - (__personality_routine)(long)(frameInfo.handler); + (__personality_routine)(intptr_t)(frameInfo.handler); _LIBUNWIND_TRACE_UNWINDING( - "unwind_phase2_forced(ex_ojb=%p): calling personality function %p\n", + "unwind_phase2_forced(ex_ojb=%p): calling personality function %p", (void *)exception_object, (void *)(uintptr_t)p); _Unwind_Reason_Code personalityResult = (*p)(1, action, exception_object->exception_class, exception_object, @@ -298,14 +300,14 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor, case _URC_CONTINUE_UNWIND: _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " "personality returned " - "_URC_CONTINUE_UNWIND\n", + "_URC_CONTINUE_UNWIND", (void *)exception_object); // Destructors called, continue unwinding break; case _URC_INSTALL_CONTEXT: _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " "personality returned " - "_URC_INSTALL_CONTEXT\n", + "_URC_INSTALL_CONTEXT", (void *)exception_object); // We may get control back if landing pad calls _Unwind_Resume(). unw_resume(cursor); @@ -314,7 +316,7 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor, // Personality routine returned an unknown result code. _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " "personality returned %d, " - "_URC_FATAL_PHASE2_ERROR\n", + "_URC_FATAL_PHASE2_ERROR", (void *)exception_object, personalityResult); return _URC_FATAL_PHASE2_ERROR; } @@ -324,7 +326,7 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor, // Call stop function one last time and tell it we've reached the end // of the stack. _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop " - "function with _UA_END_OF_STACK\n", + "function with _UA_END_OF_STACK", (void *)exception_object); _Unwind_Action lastAction = (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK); @@ -340,7 +342,7 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor, /// Called by __cxa_throw. Only returns if there is a fatal error. _LIBUNWIND_EXPORT _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception *exception_object) { - _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)\n", + _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)", (void *)exception_object); unw_context_t uc; unw_cursor_t cursor; @@ -375,7 +377,7 @@ _Unwind_RaiseException(_Unwind_Exception *exception_object) { /// in turn calls _Unwind_Resume_or_Rethrow(). _LIBUNWIND_EXPORT void _Unwind_Resume(_Unwind_Exception *exception_object) { - _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)\n", (void *)exception_object); + _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)", (void *)exception_object); unw_context_t uc; unw_cursor_t cursor; unw_getcontext(&uc); @@ -399,7 +401,7 @@ _Unwind_Resume(_Unwind_Exception *exception_object) { _LIBUNWIND_EXPORT _Unwind_Reason_Code _Unwind_ForcedUnwind(_Unwind_Exception *exception_object, _Unwind_Stop_Fn stop, void *stop_parameter) { - _LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)\n", + _LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)", (void *)exception_object, (void *)(uintptr_t)stop); unw_context_t uc; unw_cursor_t cursor; @@ -424,11 +426,11 @@ _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { if (unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) result = (uintptr_t)frameInfo.lsda; _LIBUNWIND_TRACE_API( - "_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR "\n", + "_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR, (void *)context, result); if (result != 0) { if (*((uint8_t *)result) != 0xFF) - _LIBUNWIND_DEBUG_LOG("lsda at 0x%" PRIxPTR " does not start with 0xFF\n", + _LIBUNWIND_DEBUG_LOG("lsda at 0x%" PRIxPTR " does not start with 0xFF", result); } return result; @@ -444,17 +446,18 @@ _Unwind_GetRegionStart(struct _Unwind_Context *context) { uintptr_t result = 0; if (unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) result = (uintptr_t)frameInfo.start_ip; - _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%" PRIxPTR "\n", + _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%" PRIxPTR, (void *)context, result); return result; } +#endif // !_LIBUNWIND_SUPPORT_SEH_UNWIND /// Called by personality handler during phase 2 if a foreign exception // is caught. _LIBUNWIND_EXPORT void _Unwind_DeleteException(_Unwind_Exception *exception_object) { - _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)\n", + _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)", (void *)exception_object); if (exception_object->exception_cleanup != NULL) (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, @@ -467,17 +470,17 @@ _Unwind_GetGR(struct _Unwind_Context *context, int index) { unw_cursor_t *cursor = (unw_cursor_t *)context; unw_word_t result; unw_get_reg(cursor, index, &result); - _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%" PRIx64 "\n", - (void *)context, index, (uint64_t)result); + _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%" PRIxPTR, + (void *)context, index, result); return (uintptr_t)result; } /// Called by personality handler during phase 2 to alter register values. _LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index, uintptr_t value) { - _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0" PRIx64 - ")\n", - (void *)context, index, (uint64_t)value); + _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0" PRIxPTR + ")", + (void *)context, index, value); unw_cursor_t *cursor = (unw_cursor_t *)context; unw_set_reg(cursor, index, value); } @@ -487,8 +490,8 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) { unw_cursor_t *cursor = (unw_cursor_t *)context; unw_word_t result; unw_get_reg(cursor, UNW_REG_IP, &result); - _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIx64 "\n", - (void *)context, (uint64_t)result); + _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIxPTR, + (void *)context, result); return (uintptr_t)result; } @@ -497,10 +500,10 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) { /// start executing in the landing pad. _LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context, uintptr_t value) { - _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0" PRIx64 ")\n", - (void *)context, (uint64_t)value); + _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0" PRIxPTR ")", + (void *)context, value); unw_cursor_t *cursor = (unw_cursor_t *)context; unw_set_reg(cursor, UNW_REG_IP, value); } -#endif // !_LIBUNWIND_ARM_EHABI +#endif // !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__) diff --git a/src/UnwindRegistersRestore.S b/src/UnwindRegistersRestore.S index d5ecc6ed2ac..389db67579c 100644 --- a/src/UnwindRegistersRestore.S +++ b/src/UnwindRegistersRestore.S @@ -11,11 +11,17 @@ .text +#if !defined(__USING_SJLJ_EXCEPTIONS__) + #if defined(__i386__) DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_x866jumptoEv) # # void libunwind::Registers_x86::jumpto() # +#if defined(_WIN32) +# On windows, the 'this' pointer is passed in ecx instead of on the stack + movl %ecx, %eax +#else # On entry: # + + # +-----------------------+ @@ -25,6 +31,7 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_x866jumptoEv) # +-----------------------+ <-- SP # + + movl 4(%esp), %eax +#endif # set up eax and ret on new stack location movl 28(%eax), %edx # edx holds new stack pointer subl $8,%edx @@ -58,7 +65,16 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind16Registers_x86_646jumptoEv) # # void libunwind::Registers_x86_64::jumpto() # +#if defined(_WIN64) +# On entry, thread_state pointer is in rcx; move it into rdi +# to share restore code below. Since this routine restores and +# overwrites all registers, we can use the same registers for +# pointers and temporaries as on unix even though win64 normally +# mustn't clobber some of them. + movq %rcx, %rdi +#else # On entry, thread_state pointer is in rdi +#endif movq 56(%rdi), %rax # rax holds new stack pointer subq $16, %rax @@ -88,11 +104,295 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind16Registers_x86_646jumptoEv) # skip cs # skip fs # skip gs + +#if defined(_WIN64) + movdqu 176(%rdi),%xmm0 + movdqu 192(%rdi),%xmm1 + movdqu 208(%rdi),%xmm2 + movdqu 224(%rdi),%xmm3 + movdqu 240(%rdi),%xmm4 + movdqu 256(%rdi),%xmm5 + movdqu 272(%rdi),%xmm6 + movdqu 288(%rdi),%xmm7 + movdqu 304(%rdi),%xmm8 + movdqu 320(%rdi),%xmm9 + movdqu 336(%rdi),%xmm10 + movdqu 352(%rdi),%xmm11 + movdqu 368(%rdi),%xmm12 + movdqu 384(%rdi),%xmm13 + movdqu 400(%rdi),%xmm14 + movdqu 416(%rdi),%xmm15 +#endif movq 56(%rdi), %rsp # cut back rsp to new location pop %rdi # rdi was saved here earlier ret # rip was saved here +#elif defined(__powerpc64__) + +DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind15Registers_ppc646jumptoEv) +// +// void libunwind::Registers_ppc64::jumpto() +// +// On entry: +// thread_state pointer is in r3 +// + +// load register (GPR) +#define PPC64_LR(n) \ + ld %r##n, (8 * (n + 2))(%r3) + + // restore integral registers + // skip r0 for now + // skip r1 for now + PPC64_LR(2) + // skip r3 for now + // skip r4 for now + // skip r5 for now + PPC64_LR(6) + PPC64_LR(7) + PPC64_LR(8) + PPC64_LR(9) + PPC64_LR(10) + PPC64_LR(11) + PPC64_LR(12) + PPC64_LR(13) + PPC64_LR(14) + PPC64_LR(15) + PPC64_LR(16) + PPC64_LR(17) + PPC64_LR(18) + PPC64_LR(19) + PPC64_LR(20) + PPC64_LR(21) + PPC64_LR(22) + PPC64_LR(23) + PPC64_LR(24) + PPC64_LR(25) + PPC64_LR(26) + PPC64_LR(27) + PPC64_LR(28) + PPC64_LR(29) + PPC64_LR(30) + PPC64_LR(31) + +#ifdef PPC64_HAS_VMX + + // restore VS registers + // (note that this also restores floating point registers and V registers, + // because part of VS is mapped to these registers) + + addi %r4, %r3, PPC64_OFFS_FP + +// load VS register +#define PPC64_LVS(n) \ + lxvd2x %vs##n, 0, %r4 ;\ + addi %r4, %r4, 16 + + // restore the first 32 VS regs (and also all floating point regs) + PPC64_LVS(0) + PPC64_LVS(1) + PPC64_LVS(2) + PPC64_LVS(3) + PPC64_LVS(4) + PPC64_LVS(5) + PPC64_LVS(6) + PPC64_LVS(7) + PPC64_LVS(8) + PPC64_LVS(9) + PPC64_LVS(10) + PPC64_LVS(11) + PPC64_LVS(12) + PPC64_LVS(13) + PPC64_LVS(14) + PPC64_LVS(15) + PPC64_LVS(16) + PPC64_LVS(17) + PPC64_LVS(18) + PPC64_LVS(19) + PPC64_LVS(20) + PPC64_LVS(21) + PPC64_LVS(22) + PPC64_LVS(23) + PPC64_LVS(24) + PPC64_LVS(25) + PPC64_LVS(26) + PPC64_LVS(27) + PPC64_LVS(28) + PPC64_LVS(29) + PPC64_LVS(30) + PPC64_LVS(31) + + // use VRSAVE to conditionally restore the remaining VS regs, + // that are where the V regs are mapped + + ld %r5, PPC64_OFFS_VRSAVE(%r3) // test VRsave + cmpwi %r5, 0 + beq Lnovec + +// conditionally load VS +#define PPC64_CLVS_BOTTOM(n) \ + beq Ldone##n ;\ + addi %r4, %r3, PPC64_OFFS_FP + n * 16 ;\ + lxvd2x %vs##n, 0, %r4 ;\ +Ldone##n: + +#define PPC64_CLVSl(n) \ + andis. %r0, %r5, (1<<(47-n)) ;\ +PPC64_CLVS_BOTTOM(n) + +#define PPC64_CLVSh(n) \ + andi. %r0, %r5, (1<<(63-n)) ;\ +PPC64_CLVS_BOTTOM(n) + + PPC64_CLVSl(32) + PPC64_CLVSl(33) + PPC64_CLVSl(34) + PPC64_CLVSl(35) + PPC64_CLVSl(36) + PPC64_CLVSl(37) + PPC64_CLVSl(38) + PPC64_CLVSl(39) + PPC64_CLVSl(40) + PPC64_CLVSl(41) + PPC64_CLVSl(42) + PPC64_CLVSl(43) + PPC64_CLVSl(44) + PPC64_CLVSl(45) + PPC64_CLVSl(46) + PPC64_CLVSl(47) + PPC64_CLVSh(48) + PPC64_CLVSh(49) + PPC64_CLVSh(50) + PPC64_CLVSh(51) + PPC64_CLVSh(52) + PPC64_CLVSh(53) + PPC64_CLVSh(54) + PPC64_CLVSh(55) + PPC64_CLVSh(56) + PPC64_CLVSh(57) + PPC64_CLVSh(58) + PPC64_CLVSh(59) + PPC64_CLVSh(60) + PPC64_CLVSh(61) + PPC64_CLVSh(62) + PPC64_CLVSh(63) + +#else + +// load FP register +#define PPC64_LF(n) \ + lfd %f##n, (PPC64_OFFS_FP + n * 16)(%r3) + + // restore float registers + PPC64_LF(0) + PPC64_LF(1) + PPC64_LF(2) + PPC64_LF(3) + PPC64_LF(4) + PPC64_LF(5) + PPC64_LF(6) + PPC64_LF(7) + PPC64_LF(8) + PPC64_LF(9) + PPC64_LF(10) + PPC64_LF(11) + PPC64_LF(12) + PPC64_LF(13) + PPC64_LF(14) + PPC64_LF(15) + PPC64_LF(16) + PPC64_LF(17) + PPC64_LF(18) + PPC64_LF(19) + PPC64_LF(20) + PPC64_LF(21) + PPC64_LF(22) + PPC64_LF(23) + PPC64_LF(24) + PPC64_LF(25) + PPC64_LF(26) + PPC64_LF(27) + PPC64_LF(28) + PPC64_LF(29) + PPC64_LF(30) + PPC64_LF(31) + + // restore vector registers if any are in use + ld %r5, PPC64_OFFS_VRSAVE(%r3) // test VRsave + cmpwi %r5, 0 + beq Lnovec + + subi %r4, %r1, 16 + // r4 is now a 16-byte aligned pointer into the red zone + // the _vectorScalarRegisters may not be 16-byte aligned + // so copy via red zone temp buffer + +#define PPC64_CLV_UNALIGNED_BOTTOM(n) \ + beq Ldone##n ;\ + ld %r0, (PPC64_OFFS_V + n * 16)(%r3) ;\ + std %r0, 0(%r4) ;\ + ld %r0, (PPC64_OFFS_V + n * 16 + 8)(%r3) ;\ + std %r0, 8(%r4) ;\ + lvx %v##n, 0, %r4 ;\ +Ldone ## n: + +#define PPC64_CLV_UNALIGNEDl(n) \ + andis. %r0, %r5, (1<<(15-n)) ;\ +PPC64_CLV_UNALIGNED_BOTTOM(n) + +#define PPC64_CLV_UNALIGNEDh(n) \ + andi. %r0, %r5, (1<<(31-n)) ;\ +PPC64_CLV_UNALIGNED_BOTTOM(n) + + PPC64_CLV_UNALIGNEDl(0) + PPC64_CLV_UNALIGNEDl(1) + PPC64_CLV_UNALIGNEDl(2) + PPC64_CLV_UNALIGNEDl(3) + PPC64_CLV_UNALIGNEDl(4) + PPC64_CLV_UNALIGNEDl(5) + PPC64_CLV_UNALIGNEDl(6) + PPC64_CLV_UNALIGNEDl(7) + PPC64_CLV_UNALIGNEDl(8) + PPC64_CLV_UNALIGNEDl(9) + PPC64_CLV_UNALIGNEDl(10) + PPC64_CLV_UNALIGNEDl(11) + PPC64_CLV_UNALIGNEDl(12) + PPC64_CLV_UNALIGNEDl(13) + PPC64_CLV_UNALIGNEDl(14) + PPC64_CLV_UNALIGNEDl(15) + PPC64_CLV_UNALIGNEDh(16) + PPC64_CLV_UNALIGNEDh(17) + PPC64_CLV_UNALIGNEDh(18) + PPC64_CLV_UNALIGNEDh(19) + PPC64_CLV_UNALIGNEDh(20) + PPC64_CLV_UNALIGNEDh(21) + PPC64_CLV_UNALIGNEDh(22) + PPC64_CLV_UNALIGNEDh(23) + PPC64_CLV_UNALIGNEDh(24) + PPC64_CLV_UNALIGNEDh(25) + PPC64_CLV_UNALIGNEDh(26) + PPC64_CLV_UNALIGNEDh(27) + PPC64_CLV_UNALIGNEDh(28) + PPC64_CLV_UNALIGNEDh(29) + PPC64_CLV_UNALIGNEDh(30) + PPC64_CLV_UNALIGNEDh(31) + +#endif + +Lnovec: + ld %r0, PPC64_OFFS_CR(%r3) + mtcr %r0 + ld %r0, PPC64_OFFS_SRR0(%r3) + mtctr %r0 + + PPC64_LR(0) + PPC64_LR(5) + PPC64_LR(4) + PPC64_LR(1) + PPC64_LR(3) + bctr + #elif defined(__ppc__) DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv) @@ -322,9 +622,18 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind15Registers_arm646jumptoEv) @ .p2align 2 DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm20restoreCoreAndJumpToEv) -#if !defined(__ARM_ARCH_ISA_ARM) - ldr r2, [r0, #52] - ldr r3, [r0, #60] +#if !defined(__ARM_ARCH_ISA_ARM) && __ARM_ARCH_ISA_THUMB == 1 + @ r8-r11: ldm into r1-r4, then mov to r8-r11 + adds r0, #0x20 + ldm r0!, {r1-r4} + subs r0, #0x30 + mov r8, r1 + mov r9, r2 + mov r10, r3 + mov r11, r4 + @ r12 does not need loading, it it the intra-procedure-call scratch register + ldr r2, [r0, #0x34] + ldr r3, [r0, #0x3c] mov sp, r2 mov lr, r3 @ restore pc into lr ldm r0, {r0-r7} @@ -347,7 +656,9 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm20restoreCoreAndJu @ values pointer is in r0 @ .p2align 2 +#if defined(__ELF__) .fpu vfpv3-d16 +#endif DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMDEPy) @ VFP and iwMMX instructions are only available when compiling with the flags @ that enable them. We do not want to do that in the library (because we do not @@ -366,7 +677,9 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFL @ values pointer is in r0 @ .p2align 2 +#if defined(__ELF__) .fpu vfpv3-d16 +#endif DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMXEPy) vldmia r0, {d0-d15} @ fldmiax is deprecated in ARMv7+ and now behaves like vldmia JMP(lr) @@ -378,11 +691,15 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFL @ values pointer is in r0 @ .p2align 2 +#if defined(__ELF__) .fpu vfpv3 +#endif DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreVFPv3EPy) vldmia r0, {d16-d31} JMP(lr) +#if defined(__ARM_WMMX) + @ @ static void libunwind::Registers_arm::restoreiWMMX(unw_fpreg_t* values) @ @@ -390,8 +707,10 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreVFPv3EPy) @ values pointer is in r0 @ .p2align 2 +#if defined(__ELF__) + .arch armv5te +#endif DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreiWMMXEPy) -#if (!defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_6SM__)) || defined(__ARM_WMMX) ldcl p1, cr0, [r0], #8 @ wldrd wR0, [r0], #8 ldcl p1, cr1, [r0], #8 @ wldrd wR1, [r0], #8 ldcl p1, cr2, [r0], #8 @ wldrd wR2, [r0], #8 @@ -408,7 +727,6 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreiWMMXEPy) ldcl p1, cr13, [r0], #8 @ wldrd wR13, [r0], #8 ldcl p1, cr14, [r0], #8 @ wldrd wR14, [r0], #8 ldcl p1, cr15, [r0], #8 @ wldrd wR15, [r0], #8 -#endif JMP(lr) @ @@ -418,15 +736,18 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreiWMMXEPy) @ values pointer is in r0 @ .p2align 2 +#if defined(__ELF__) + .arch armv5te +#endif DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreiWMMXControlEPj) -#if (!defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_6SM__)) || defined(__ARM_WMMX) ldc2 p1, cr8, [r0], #4 @ wldrw wCGR0, [r0], #4 ldc2 p1, cr9, [r0], #4 @ wldrw wCGR1, [r0], #4 ldc2 p1, cr10, [r0], #4 @ wldrw wCGR2, [r0], #4 ldc2 p1, cr11, [r0], #4 @ wldrw wCGR3, [r0], #4 -#endif JMP(lr) +#endif + #elif defined(__or1k__) DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv) @@ -437,7 +758,7 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv) # thread_state pointer is in r3 # - # restore integral registerrs + # restore integral registers l.lwz r0, 0(r3) l.lwz r1, 4(r3) l.lwz r2, 8(r3) @@ -447,7 +768,7 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv) l.lwz r6, 24(r3) l.lwz r7, 28(r3) l.lwz r8, 32(r3) - l.lwz r9, 36(r3) + # skip r9 l.lwz r10, 40(r3) l.lwz r11, 44(r3) l.lwz r12, 48(r3) @@ -474,8 +795,236 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv) # at last, restore r3 l.lwz r3, 12(r3) + # load new pc into ra + l.lwz r9, 128(r3) # jump to pc l.jr r9 l.nop +#elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32 + +// +// void libunwind::Registers_mips_o32::jumpto() +// +// On entry: +// thread state pointer is in a0 ($4) +// +DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind18Registers_mips_o326jumptoEv) + .set push + .set noat + .set noreorder + .set nomacro +#ifdef __mips_hard_float +#if __mips_fpr != 64 + ldc1 $f0, (4 * 36 + 8 * 0)($4) + ldc1 $f2, (4 * 36 + 8 * 2)($4) + ldc1 $f4, (4 * 36 + 8 * 4)($4) + ldc1 $f6, (4 * 36 + 8 * 6)($4) + ldc1 $f8, (4 * 36 + 8 * 8)($4) + ldc1 $f10, (4 * 36 + 8 * 10)($4) + ldc1 $f12, (4 * 36 + 8 * 12)($4) + ldc1 $f14, (4 * 36 + 8 * 14)($4) + ldc1 $f16, (4 * 36 + 8 * 16)($4) + ldc1 $f18, (4 * 36 + 8 * 18)($4) + ldc1 $f20, (4 * 36 + 8 * 20)($4) + ldc1 $f22, (4 * 36 + 8 * 22)($4) + ldc1 $f24, (4 * 36 + 8 * 24)($4) + ldc1 $f26, (4 * 36 + 8 * 26)($4) + ldc1 $f28, (4 * 36 + 8 * 28)($4) + ldc1 $f30, (4 * 36 + 8 * 30)($4) +#else + ldc1 $f0, (4 * 36 + 8 * 0)($4) + ldc1 $f1, (4 * 36 + 8 * 1)($4) + ldc1 $f2, (4 * 36 + 8 * 2)($4) + ldc1 $f3, (4 * 36 + 8 * 3)($4) + ldc1 $f4, (4 * 36 + 8 * 4)($4) + ldc1 $f5, (4 * 36 + 8 * 5)($4) + ldc1 $f6, (4 * 36 + 8 * 6)($4) + ldc1 $f7, (4 * 36 + 8 * 7)($4) + ldc1 $f8, (4 * 36 + 8 * 8)($4) + ldc1 $f9, (4 * 36 + 8 * 9)($4) + ldc1 $f10, (4 * 36 + 8 * 10)($4) + ldc1 $f11, (4 * 36 + 8 * 11)($4) + ldc1 $f12, (4 * 36 + 8 * 12)($4) + ldc1 $f13, (4 * 36 + 8 * 13)($4) + ldc1 $f14, (4 * 36 + 8 * 14)($4) + ldc1 $f15, (4 * 36 + 8 * 15)($4) + ldc1 $f16, (4 * 36 + 8 * 16)($4) + ldc1 $f17, (4 * 36 + 8 * 17)($4) + ldc1 $f18, (4 * 36 + 8 * 18)($4) + ldc1 $f19, (4 * 36 + 8 * 19)($4) + ldc1 $f20, (4 * 36 + 8 * 20)($4) + ldc1 $f21, (4 * 36 + 8 * 21)($4) + ldc1 $f22, (4 * 36 + 8 * 22)($4) + ldc1 $f23, (4 * 36 + 8 * 23)($4) + ldc1 $f24, (4 * 36 + 8 * 24)($4) + ldc1 $f25, (4 * 36 + 8 * 25)($4) + ldc1 $f26, (4 * 36 + 8 * 26)($4) + ldc1 $f27, (4 * 36 + 8 * 27)($4) + ldc1 $f28, (4 * 36 + 8 * 28)($4) + ldc1 $f29, (4 * 36 + 8 * 29)($4) + ldc1 $f30, (4 * 36 + 8 * 30)($4) + ldc1 $f31, (4 * 36 + 8 * 31)($4) #endif +#endif + // restore hi and lo + lw $8, (4 * 33)($4) + mthi $8 + lw $8, (4 * 34)($4) + mtlo $8 + // r0 is zero + lw $1, (4 * 1)($4) + lw $2, (4 * 2)($4) + lw $3, (4 * 3)($4) + // skip a0 for now + lw $5, (4 * 5)($4) + lw $6, (4 * 6)($4) + lw $7, (4 * 7)($4) + lw $8, (4 * 8)($4) + lw $9, (4 * 9)($4) + lw $10, (4 * 10)($4) + lw $11, (4 * 11)($4) + lw $12, (4 * 12)($4) + lw $13, (4 * 13)($4) + lw $14, (4 * 14)($4) + lw $15, (4 * 15)($4) + lw $16, (4 * 16)($4) + lw $17, (4 * 17)($4) + lw $18, (4 * 18)($4) + lw $19, (4 * 19)($4) + lw $20, (4 * 20)($4) + lw $21, (4 * 21)($4) + lw $22, (4 * 22)($4) + lw $23, (4 * 23)($4) + lw $24, (4 * 24)($4) + lw $25, (4 * 25)($4) + lw $26, (4 * 26)($4) + lw $27, (4 * 27)($4) + lw $28, (4 * 28)($4) + lw $29, (4 * 29)($4) + lw $30, (4 * 30)($4) + // load new pc into ra + lw $31, (4 * 32)($4) + // jump to ra, load a0 in the delay slot + jr $31 + lw $4, (4 * 4)($4) + .set pop + +#elif defined(__mips64) + +// +// void libunwind::Registers_mips_newabi::jumpto() +// +// On entry: +// thread state pointer is in a0 ($4) +// +DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind21Registers_mips_newabi6jumptoEv) + .set push + .set noat + .set noreorder + .set nomacro +#ifdef __mips_hard_float + ldc1 $f0, (8 * 35)($4) + ldc1 $f1, (8 * 36)($4) + ldc1 $f2, (8 * 37)($4) + ldc1 $f3, (8 * 38)($4) + ldc1 $f4, (8 * 39)($4) + ldc1 $f5, (8 * 40)($4) + ldc1 $f6, (8 * 41)($4) + ldc1 $f7, (8 * 42)($4) + ldc1 $f8, (8 * 43)($4) + ldc1 $f9, (8 * 44)($4) + ldc1 $f10, (8 * 45)($4) + ldc1 $f11, (8 * 46)($4) + ldc1 $f12, (8 * 47)($4) + ldc1 $f13, (8 * 48)($4) + ldc1 $f14, (8 * 49)($4) + ldc1 $f15, (8 * 50)($4) + ldc1 $f16, (8 * 51)($4) + ldc1 $f17, (8 * 52)($4) + ldc1 $f18, (8 * 53)($4) + ldc1 $f19, (8 * 54)($4) + ldc1 $f20, (8 * 55)($4) + ldc1 $f21, (8 * 56)($4) + ldc1 $f22, (8 * 57)($4) + ldc1 $f23, (8 * 58)($4) + ldc1 $f24, (8 * 59)($4) + ldc1 $f25, (8 * 60)($4) + ldc1 $f26, (8 * 61)($4) + ldc1 $f27, (8 * 62)($4) + ldc1 $f28, (8 * 63)($4) + ldc1 $f29, (8 * 64)($4) + ldc1 $f30, (8 * 65)($4) + ldc1 $f31, (8 * 66)($4) +#endif + // restore hi and lo + ld $8, (8 * 33)($4) + mthi $8 + ld $8, (8 * 34)($4) + mtlo $8 + // r0 is zero + ld $1, (8 * 1)($4) + ld $2, (8 * 2)($4) + ld $3, (8 * 3)($4) + // skip a0 for now + ld $5, (8 * 5)($4) + ld $6, (8 * 6)($4) + ld $7, (8 * 7)($4) + ld $8, (8 * 8)($4) + ld $9, (8 * 9)($4) + ld $10, (8 * 10)($4) + ld $11, (8 * 11)($4) + ld $12, (8 * 12)($4) + ld $13, (8 * 13)($4) + ld $14, (8 * 14)($4) + ld $15, (8 * 15)($4) + ld $16, (8 * 16)($4) + ld $17, (8 * 17)($4) + ld $18, (8 * 18)($4) + ld $19, (8 * 19)($4) + ld $20, (8 * 20)($4) + ld $21, (8 * 21)($4) + ld $22, (8 * 22)($4) + ld $23, (8 * 23)($4) + ld $24, (8 * 24)($4) + ld $25, (8 * 25)($4) + ld $26, (8 * 26)($4) + ld $27, (8 * 27)($4) + ld $28, (8 * 28)($4) + ld $29, (8 * 29)($4) + ld $30, (8 * 30)($4) + // load new pc into ra + ld $31, (8 * 32)($4) + // jump to ra, load a0 in the delay slot + jr $31 + ld $4, (8 * 4)($4) + .set pop + +#elif defined(__sparc__) + +// +// void libunwind::Registers_sparc_o32::jumpto() +// +// On entry: +// thread_state pointer is in o0 +// +DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind15Registers_sparc6jumptoEv) + ta 3 + ldd [%o0 + 64], %l0 + ldd [%o0 + 72], %l2 + ldd [%o0 + 80], %l4 + ldd [%o0 + 88], %l6 + ldd [%o0 + 96], %i0 + ldd [%o0 + 104], %i2 + ldd [%o0 + 112], %i4 + ldd [%o0 + 120], %i6 + ld [%o0 + 60], %o7 + jmp %o7 + nop + +#endif + +#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */ + +NO_EXEC_STACK_DIRECTIVE + diff --git a/src/UnwindRegistersSave.S b/src/UnwindRegistersSave.S index 82becffa0e4..48ecb0aec70 100644 --- a/src/UnwindRegistersSave.S +++ b/src/UnwindRegistersSave.S @@ -11,6 +11,8 @@ .text +#if !defined(__USING_SJLJ_EXCEPTIONS__) + #if defined(__i386__) # @@ -61,32 +63,258 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) # thread_state pointer is in rdi # DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) - movq %rax, (%rdi) - movq %rbx, 8(%rdi) - movq %rcx, 16(%rdi) - movq %rdx, 24(%rdi) - movq %rdi, 32(%rdi) - movq %rsi, 40(%rdi) - movq %rbp, 48(%rdi) - movq %rsp, 56(%rdi) - addq $8, 56(%rdi) - movq %r8, 64(%rdi) - movq %r9, 72(%rdi) - movq %r10, 80(%rdi) - movq %r11, 88(%rdi) - movq %r12, 96(%rdi) - movq %r13,104(%rdi) - movq %r14,112(%rdi) - movq %r15,120(%rdi) - movq (%rsp),%rsi - movq %rsi,128(%rdi) # store return address as rip +#if defined(_WIN64) +#define PTR %rcx +#define TMP %rdx +#else +#define PTR %rdi +#define TMP %rsi +#endif + + movq %rax, (PTR) + movq %rbx, 8(PTR) + movq %rcx, 16(PTR) + movq %rdx, 24(PTR) + movq %rdi, 32(PTR) + movq %rsi, 40(PTR) + movq %rbp, 48(PTR) + movq %rsp, 56(PTR) + addq $8, 56(PTR) + movq %r8, 64(PTR) + movq %r9, 72(PTR) + movq %r10, 80(PTR) + movq %r11, 88(PTR) + movq %r12, 96(PTR) + movq %r13,104(PTR) + movq %r14,112(PTR) + movq %r15,120(PTR) + movq (%rsp),TMP + movq TMP,128(PTR) # store return address as rip # skip rflags # skip cs # skip fs # skip gs + +#if defined(_WIN64) + movdqu %xmm0,176(PTR) + movdqu %xmm1,192(PTR) + movdqu %xmm2,208(PTR) + movdqu %xmm3,224(PTR) + movdqu %xmm4,240(PTR) + movdqu %xmm5,256(PTR) + movdqu %xmm6,272(PTR) + movdqu %xmm7,288(PTR) + movdqu %xmm8,304(PTR) + movdqu %xmm9,320(PTR) + movdqu %xmm10,336(PTR) + movdqu %xmm11,352(PTR) + movdqu %xmm12,368(PTR) + movdqu %xmm13,384(PTR) + movdqu %xmm14,400(PTR) + movdqu %xmm15,416(PTR) +#endif xorl %eax, %eax # return UNW_ESUCCESS ret +#elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32 + +# +# extern int unw_getcontext(unw_context_t* thread_state) +# +# On entry: +# thread_state pointer is in a0 ($4) +# +DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) + .set push + .set noat + .set noreorder + .set nomacro + sw $1, (4 * 1)($4) + sw $2, (4 * 2)($4) + sw $3, (4 * 3)($4) + sw $4, (4 * 4)($4) + sw $5, (4 * 5)($4) + sw $6, (4 * 6)($4) + sw $7, (4 * 7)($4) + sw $8, (4 * 8)($4) + sw $9, (4 * 9)($4) + sw $10, (4 * 10)($4) + sw $11, (4 * 11)($4) + sw $12, (4 * 12)($4) + sw $13, (4 * 13)($4) + sw $14, (4 * 14)($4) + sw $15, (4 * 15)($4) + sw $16, (4 * 16)($4) + sw $17, (4 * 17)($4) + sw $18, (4 * 18)($4) + sw $19, (4 * 19)($4) + sw $20, (4 * 20)($4) + sw $21, (4 * 21)($4) + sw $22, (4 * 22)($4) + sw $23, (4 * 23)($4) + sw $24, (4 * 24)($4) + sw $25, (4 * 25)($4) + sw $26, (4 * 26)($4) + sw $27, (4 * 27)($4) + sw $28, (4 * 28)($4) + sw $29, (4 * 29)($4) + sw $30, (4 * 30)($4) + sw $31, (4 * 31)($4) + # Store return address to pc + sw $31, (4 * 32)($4) + # hi and lo + mfhi $8 + sw $8, (4 * 33)($4) + mflo $8 + sw $8, (4 * 34)($4) +#ifdef __mips_hard_float +#if __mips_fpr != 64 + sdc1 $f0, (4 * 36 + 8 * 0)($4) + sdc1 $f2, (4 * 36 + 8 * 2)($4) + sdc1 $f4, (4 * 36 + 8 * 4)($4) + sdc1 $f6, (4 * 36 + 8 * 6)($4) + sdc1 $f8, (4 * 36 + 8 * 8)($4) + sdc1 $f10, (4 * 36 + 8 * 10)($4) + sdc1 $f12, (4 * 36 + 8 * 12)($4) + sdc1 $f14, (4 * 36 + 8 * 14)($4) + sdc1 $f16, (4 * 36 + 8 * 16)($4) + sdc1 $f18, (4 * 36 + 8 * 18)($4) + sdc1 $f20, (4 * 36 + 8 * 20)($4) + sdc1 $f22, (4 * 36 + 8 * 22)($4) + sdc1 $f24, (4 * 36 + 8 * 24)($4) + sdc1 $f26, (4 * 36 + 8 * 26)($4) + sdc1 $f28, (4 * 36 + 8 * 28)($4) + sdc1 $f30, (4 * 36 + 8 * 30)($4) +#else + sdc1 $f0, (4 * 36 + 8 * 0)($4) + sdc1 $f1, (4 * 36 + 8 * 1)($4) + sdc1 $f2, (4 * 36 + 8 * 2)($4) + sdc1 $f3, (4 * 36 + 8 * 3)($4) + sdc1 $f4, (4 * 36 + 8 * 4)($4) + sdc1 $f5, (4 * 36 + 8 * 5)($4) + sdc1 $f6, (4 * 36 + 8 * 6)($4) + sdc1 $f7, (4 * 36 + 8 * 7)($4) + sdc1 $f8, (4 * 36 + 8 * 8)($4) + sdc1 $f9, (4 * 36 + 8 * 9)($4) + sdc1 $f10, (4 * 36 + 8 * 10)($4) + sdc1 $f11, (4 * 36 + 8 * 11)($4) + sdc1 $f12, (4 * 36 + 8 * 12)($4) + sdc1 $f13, (4 * 36 + 8 * 13)($4) + sdc1 $f14, (4 * 36 + 8 * 14)($4) + sdc1 $f15, (4 * 36 + 8 * 15)($4) + sdc1 $f16, (4 * 36 + 8 * 16)($4) + sdc1 $f17, (4 * 36 + 8 * 17)($4) + sdc1 $f18, (4 * 36 + 8 * 18)($4) + sdc1 $f19, (4 * 36 + 8 * 19)($4) + sdc1 $f20, (4 * 36 + 8 * 20)($4) + sdc1 $f21, (4 * 36 + 8 * 21)($4) + sdc1 $f22, (4 * 36 + 8 * 22)($4) + sdc1 $f23, (4 * 36 + 8 * 23)($4) + sdc1 $f24, (4 * 36 + 8 * 24)($4) + sdc1 $f25, (4 * 36 + 8 * 25)($4) + sdc1 $f26, (4 * 36 + 8 * 26)($4) + sdc1 $f27, (4 * 36 + 8 * 27)($4) + sdc1 $f28, (4 * 36 + 8 * 28)($4) + sdc1 $f29, (4 * 36 + 8 * 29)($4) + sdc1 $f30, (4 * 36 + 8 * 30)($4) + sdc1 $f31, (4 * 36 + 8 * 31)($4) +#endif +#endif + jr $31 + # return UNW_ESUCCESS + or $2, $0, $0 + .set pop + +#elif defined(__mips64) + +# +# extern int unw_getcontext(unw_context_t* thread_state) +# +# On entry: +# thread_state pointer is in a0 ($4) +# +DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) + .set push + .set noat + .set noreorder + .set nomacro + sd $1, (8 * 1)($4) + sd $2, (8 * 2)($4) + sd $3, (8 * 3)($4) + sd $4, (8 * 4)($4) + sd $5, (8 * 5)($4) + sd $6, (8 * 6)($4) + sd $7, (8 * 7)($4) + sd $8, (8 * 8)($4) + sd $9, (8 * 9)($4) + sd $10, (8 * 10)($4) + sd $11, (8 * 11)($4) + sd $12, (8 * 12)($4) + sd $13, (8 * 13)($4) + sd $14, (8 * 14)($4) + sd $15, (8 * 15)($4) + sd $16, (8 * 16)($4) + sd $17, (8 * 17)($4) + sd $18, (8 * 18)($4) + sd $19, (8 * 19)($4) + sd $20, (8 * 20)($4) + sd $21, (8 * 21)($4) + sd $22, (8 * 22)($4) + sd $23, (8 * 23)($4) + sd $24, (8 * 24)($4) + sd $25, (8 * 25)($4) + sd $26, (8 * 26)($4) + sd $27, (8 * 27)($4) + sd $28, (8 * 28)($4) + sd $29, (8 * 29)($4) + sd $30, (8 * 30)($4) + sd $31, (8 * 31)($4) + # Store return address to pc + sd $31, (8 * 32)($4) + # hi and lo + mfhi $8 + sd $8, (8 * 33)($4) + mflo $8 + sd $8, (8 * 34)($4) +#ifdef __mips_hard_float + sdc1 $f0, (8 * 35)($4) + sdc1 $f1, (8 * 36)($4) + sdc1 $f2, (8 * 37)($4) + sdc1 $f3, (8 * 38)($4) + sdc1 $f4, (8 * 39)($4) + sdc1 $f5, (8 * 40)($4) + sdc1 $f6, (8 * 41)($4) + sdc1 $f7, (8 * 42)($4) + sdc1 $f8, (8 * 43)($4) + sdc1 $f9, (8 * 44)($4) + sdc1 $f10, (8 * 45)($4) + sdc1 $f11, (8 * 46)($4) + sdc1 $f12, (8 * 47)($4) + sdc1 $f13, (8 * 48)($4) + sdc1 $f14, (8 * 49)($4) + sdc1 $f15, (8 * 50)($4) + sdc1 $f16, (8 * 51)($4) + sdc1 $f17, (8 * 52)($4) + sdc1 $f18, (8 * 53)($4) + sdc1 $f19, (8 * 54)($4) + sdc1 $f20, (8 * 55)($4) + sdc1 $f21, (8 * 56)($4) + sdc1 $f22, (8 * 57)($4) + sdc1 $f23, (8 * 58)($4) + sdc1 $f24, (8 * 59)($4) + sdc1 $f25, (8 * 60)($4) + sdc1 $f26, (8 * 61)($4) + sdc1 $f27, (8 * 62)($4) + sdc1 $f28, (8 * 63)($4) + sdc1 $f29, (8 * 64)($4) + sdc1 $f30, (8 * 65)($4) + sdc1 $f31, (8 * 66)($4) +#endif + jr $31 + # return UNW_ESUCCESS + or $2, $0, $0 + .set pop + # elif defined(__mips__) # @@ -96,6 +324,237 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) teq $0, $0 +#elif defined(__powerpc64__) + +// +// extern int unw_getcontext(unw_context_t* thread_state) +// +// On entry: +// thread_state pointer is in r3 +// +DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) + +// store register (GPR) +#define PPC64_STR(n) \ + std %r##n, (8 * (n + 2))(%r3) + + // save GPRs + PPC64_STR(0) + mflr %r0 + std %r0, PPC64_OFFS_SRR0(%r3) // store lr as ssr0 + PPC64_STR(1) + PPC64_STR(2) + PPC64_STR(3) + PPC64_STR(4) + PPC64_STR(5) + PPC64_STR(6) + PPC64_STR(7) + PPC64_STR(8) + PPC64_STR(9) + PPC64_STR(10) + PPC64_STR(11) + PPC64_STR(12) + PPC64_STR(13) + PPC64_STR(14) + PPC64_STR(15) + PPC64_STR(16) + PPC64_STR(17) + PPC64_STR(18) + PPC64_STR(19) + PPC64_STR(20) + PPC64_STR(21) + PPC64_STR(22) + PPC64_STR(23) + PPC64_STR(24) + PPC64_STR(25) + PPC64_STR(26) + PPC64_STR(27) + PPC64_STR(28) + PPC64_STR(29) + PPC64_STR(30) + PPC64_STR(31) + + mfcr %r0 + std %r0, PPC64_OFFS_CR(%r3) + mfxer %r0 + std %r0, PPC64_OFFS_XER(%r3) + mflr %r0 + std %r0, PPC64_OFFS_LR(%r3) + mfctr %r0 + std %r0, PPC64_OFFS_CTR(%r3) + mfvrsave %r0 + std %r0, PPC64_OFFS_VRSAVE(%r3) + +#ifdef PPC64_HAS_VMX + // save VS registers + // (note that this also saves floating point registers and V registers, + // because part of VS is mapped to these registers) + + addi %r4, %r3, PPC64_OFFS_FP + +// store VS register +#define PPC64_STVS(n) \ + stxvd2x %vs##n, 0, %r4 ;\ + addi %r4, %r4, 16 + + PPC64_STVS(0) + PPC64_STVS(1) + PPC64_STVS(2) + PPC64_STVS(3) + PPC64_STVS(4) + PPC64_STVS(5) + PPC64_STVS(6) + PPC64_STVS(7) + PPC64_STVS(8) + PPC64_STVS(9) + PPC64_STVS(10) + PPC64_STVS(11) + PPC64_STVS(12) + PPC64_STVS(13) + PPC64_STVS(14) + PPC64_STVS(15) + PPC64_STVS(16) + PPC64_STVS(17) + PPC64_STVS(18) + PPC64_STVS(19) + PPC64_STVS(20) + PPC64_STVS(21) + PPC64_STVS(22) + PPC64_STVS(23) + PPC64_STVS(24) + PPC64_STVS(25) + PPC64_STVS(26) + PPC64_STVS(27) + PPC64_STVS(28) + PPC64_STVS(29) + PPC64_STVS(30) + PPC64_STVS(31) + PPC64_STVS(32) + PPC64_STVS(33) + PPC64_STVS(34) + PPC64_STVS(35) + PPC64_STVS(36) + PPC64_STVS(37) + PPC64_STVS(38) + PPC64_STVS(39) + PPC64_STVS(40) + PPC64_STVS(41) + PPC64_STVS(42) + PPC64_STVS(43) + PPC64_STVS(44) + PPC64_STVS(45) + PPC64_STVS(46) + PPC64_STVS(47) + PPC64_STVS(48) + PPC64_STVS(49) + PPC64_STVS(50) + PPC64_STVS(51) + PPC64_STVS(52) + PPC64_STVS(53) + PPC64_STVS(54) + PPC64_STVS(55) + PPC64_STVS(56) + PPC64_STVS(57) + PPC64_STVS(58) + PPC64_STVS(59) + PPC64_STVS(60) + PPC64_STVS(61) + PPC64_STVS(62) + PPC64_STVS(63) + +#else + +// store FP register +#define PPC64_STF(n) \ + stfd %f##n, (PPC64_OFFS_FP + n * 16)(%r3) + + // save float registers + PPC64_STF(0) + PPC64_STF(1) + PPC64_STF(2) + PPC64_STF(3) + PPC64_STF(4) + PPC64_STF(5) + PPC64_STF(6) + PPC64_STF(7) + PPC64_STF(8) + PPC64_STF(9) + PPC64_STF(10) + PPC64_STF(11) + PPC64_STF(12) + PPC64_STF(13) + PPC64_STF(14) + PPC64_STF(15) + PPC64_STF(16) + PPC64_STF(17) + PPC64_STF(18) + PPC64_STF(19) + PPC64_STF(20) + PPC64_STF(21) + PPC64_STF(22) + PPC64_STF(23) + PPC64_STF(24) + PPC64_STF(25) + PPC64_STF(26) + PPC64_STF(27) + PPC64_STF(28) + PPC64_STF(29) + PPC64_STF(30) + PPC64_STF(31) + + // save vector registers + + // Use 16-bytes below the stack pointer as an + // aligned buffer to save each vector register. + // Note that the stack pointer is always 16-byte aligned. + subi %r4, %r1, 16 + +#define PPC64_STV_UNALIGNED(n) \ + stvx %v##n, 0, %r4 ;\ + ld %r5, 0(%r4) ;\ + std %r5, (PPC64_OFFS_V + n * 16)(%r3) ;\ + ld %r5, 8(%r4) ;\ + std %r5, (PPC64_OFFS_V + n * 16 + 8)(%r3) + + PPC64_STV_UNALIGNED(0) + PPC64_STV_UNALIGNED(1) + PPC64_STV_UNALIGNED(2) + PPC64_STV_UNALIGNED(3) + PPC64_STV_UNALIGNED(4) + PPC64_STV_UNALIGNED(5) + PPC64_STV_UNALIGNED(6) + PPC64_STV_UNALIGNED(7) + PPC64_STV_UNALIGNED(8) + PPC64_STV_UNALIGNED(9) + PPC64_STV_UNALIGNED(10) + PPC64_STV_UNALIGNED(11) + PPC64_STV_UNALIGNED(12) + PPC64_STV_UNALIGNED(13) + PPC64_STV_UNALIGNED(14) + PPC64_STV_UNALIGNED(15) + PPC64_STV_UNALIGNED(16) + PPC64_STV_UNALIGNED(17) + PPC64_STV_UNALIGNED(18) + PPC64_STV_UNALIGNED(19) + PPC64_STV_UNALIGNED(20) + PPC64_STV_UNALIGNED(21) + PPC64_STV_UNALIGNED(22) + PPC64_STV_UNALIGNED(23) + PPC64_STV_UNALIGNED(24) + PPC64_STV_UNALIGNED(25) + PPC64_STV_UNALIGNED(26) + PPC64_STV_UNALIGNED(27) + PPC64_STV_UNALIGNED(28) + PPC64_STV_UNALIGNED(29) + PPC64_STV_UNALIGNED(30) + PPC64_STV_UNALIGNED(31) + +#endif + + li %r3, 0 // return UNW_ESUCCESS + blr + + #elif defined(__ppc__) ; @@ -309,13 +768,24 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) @ .p2align 2 DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) -#if !defined(__ARM_ARCH_ISA_ARM) - stm r0, {r0-r7} +#if !defined(__ARM_ARCH_ISA_ARM) && __ARM_ARCH_ISA_THUMB == 1 + stm r0!, {r0-r7} + mov r1, r8 + mov r2, r9 + mov r3, r10 + stm r0!, {r1-r3} + mov r1, r11 mov r2, sp mov r3, lr - str r2, [r0, #52] - str r3, [r0, #56] - str r3, [r0, #60] @ store return address as pc + str r1, [r0, #0] @ r11 + @ r12 does not need storing, it it the intra-procedure-call scratch register + str r2, [r0, #8] @ sp + str r3, [r0, #12] @ lr + str r3, [r0, #16] @ store return address as pc + @ T1 does not have a non-cpsr-clobbering register-zeroing instruction. + @ It is safe to use here though because we are about to return, and cpsr is + @ not expected to be preserved. + movs r0, #0 @ return UNW_ESUCCESS #else @ 32bit thumb-2 restrictions for stm: @ . the sp (r13) cannot be in the list @@ -324,13 +794,6 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) str sp, [r0, #52] str lr, [r0, #56] str lr, [r0, #60] @ store return address as pc -#endif -#if __ARM_ARCH_ISA_THUMB == 1 - @ T1 does not have a non-cpsr-clobbering register-zeroing instruction. - @ It is safe to use here though because we are about to return, and cpsr is - @ not expected to be preserved. - movs r0, #0 @ return UNW_ESUCCESS -#else mov r0, #0 @ return UNW_ESUCCESS #endif JMP(lr) @@ -342,7 +805,9 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) @ values pointer is in r0 @ .p2align 2 +#if defined(__ELF__) .fpu vfpv3-d16 +#endif DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMDEPy) vstmia r0, {d0-d15} JMP(lr) @@ -354,7 +819,9 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMD @ values pointer is in r0 @ .p2align 2 +#if defined(__ELF__) .fpu vfpv3-d16 +#endif DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMXEPy) vstmia r0, {d0-d15} @ fstmiax is deprecated in ARMv7+ and now behaves like vstmia JMP(lr) @@ -366,7 +833,9 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMX @ values pointer is in r0 @ .p2align 2 +#if defined(__ELF__) .fpu vfpv3 +#endif DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveVFPv3EPy) @ VFP and iwMMX instructions are only available when compiling with the flags @ that enable them. We do not want to do that in the library (because we do not @@ -378,6 +847,8 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveVFPv3EPy) vstmia r0, {d16-d31} JMP(lr) +#if defined(_LIBUNWIND_ARM_WMMX) + @ @ static void libunwind::Registers_arm::saveiWMMX(unw_fpreg_t* values) @ @@ -385,8 +856,10 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveVFPv3EPy) @ values pointer is in r0 @ .p2align 2 +#if defined(__ELF__) + .arch armv5te +#endif DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveiWMMXEPy) -#if (!defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_6SM__)) || defined(__ARM_WMMX) stcl p1, cr0, [r0], #8 @ wstrd wR0, [r0], #8 stcl p1, cr1, [r0], #8 @ wstrd wR1, [r0], #8 stcl p1, cr2, [r0], #8 @ wstrd wR2, [r0], #8 @@ -403,7 +876,6 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveiWMMXEPy) stcl p1, cr13, [r0], #8 @ wstrd wR13, [r0], #8 stcl p1, cr14, [r0], #8 @ wstrd wR14, [r0], #8 stcl p1, cr15, [r0], #8 @ wstrd wR15, [r0], #8 -#endif JMP(lr) @ @@ -413,15 +885,18 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveiWMMXEPy) @ values pointer is in r0 @ .p2align 2 +#if defined(__ELF__) + .arch armv5te +#endif DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveiWMMXControlEPj) -#if (!defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_6SM__)) || defined(__ARM_WMMX) stc2 p1, cr8, [r0], #4 @ wstrw wCGR0, [r0], #4 stc2 p1, cr9, [r0], #4 @ wstrw wCGR1, [r0], #4 stc2 p1, cr10, [r0], #4 @ wstrw wCGR2, [r0], #4 stc2 p1, cr11, [r0], #4 @ wstrw wCGR3, [r0], #4 -#endif JMP(lr) +#endif + #elif defined(__or1k__) # @@ -463,4 +938,41 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) l.sw 116(r3), r29 l.sw 120(r3), r30 l.sw 124(r3), r31 + # store ra to pc + l.sw 128(r3), r9 + # zero epcr + l.sw 132(r3), r0 + +#elif defined(__sparc__) + +# +# extern int unw_getcontext(unw_context_t* thread_state) +# +# On entry: +# thread_state pointer is in o0 +# +DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) + ta 3 + add %o7, 8, %o7 + std %g0, [%o0 + 0] + std %g2, [%o0 + 8] + std %g4, [%o0 + 16] + std %g6, [%o0 + 24] + std %o0, [%o0 + 32] + std %o2, [%o0 + 40] + std %o4, [%o0 + 48] + std %o6, [%o0 + 56] + std %l0, [%o0 + 64] + std %l2, [%o0 + 72] + std %l4, [%o0 + 80] + std %l6, [%o0 + 88] + std %i0, [%o0 + 96] + std %i2, [%o0 + 104] + std %i4, [%o0 + 112] + std %i6, [%o0 + 120] + jmp %o7 + clr %o0 // return UNW_ESUCCESS #endif +#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */ + +NO_EXEC_STACK_DIRECTIVE diff --git a/src/Unwind_AppleExtras.cpp b/src/Unwind_AppleExtras.cpp index b8baef5fa76..39f379c5298 100644 --- a/src/Unwind_AppleExtras.cpp +++ b/src/Unwind_AppleExtras.cpp @@ -9,8 +9,8 @@ //===----------------------------------------------------------------------===// #include "config.h" +#include "AddressSpace.hpp" #include "DwarfParser.hpp" -#include "unwind_ext.h" // private keymgr stuff @@ -76,7 +76,7 @@ struct libgcc_object_info { #endif -#if _LIBUNWIND_BUILD_ZERO_COST_APIS +#if defined(_LIBUNWIND_BUILD_ZERO_COST_APIS) // // symbols in libSystem.dylib in 10.6 and later, but are in libgcc_s.dylib in @@ -115,12 +115,12 @@ NEVER_HERE(__register_frame_table) NEVER_HERE(__deregister_frame_info) NEVER_HERE(__deregister_frame_info_bases) -#endif // _LIBUNWIND_BUILD_ZERO_COST_APIS +#endif // defined(_LIBUNWIND_BUILD_ZERO_COST_APIS) -#if _LIBUNWIND_BUILD_SJLJ_APIS +#if defined(_LIBUNWIND_BUILD_SJLJ_APIS) // // symbols in libSystem.dylib in iOS 5.0 and later, but are in libgcc_s.dylib in // earlier versions @@ -140,7 +140,7 @@ NOT_HERE_BEFORE_5_0(_Unwind_SjLj_RaiseException) NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Resume_or_Rethrow) NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Unregister) -#endif // _LIBUNWIND_BUILD_SJLJ_APIS +#endif // defined(_LIBUNWIND_BUILD_SJLJ_APIS) namespace libunwind { @@ -182,24 +182,3 @@ bool checkKeyMgrRegisteredFDEs(uintptr_t pc, void *&fde) { } - -#if !defined(FOR_DYLD) && _LIBUNWIND_BUILD_SJLJ_APIS - -#include - -// Accessors to get get/set linked list of frames for sjlj based execeptions. -_LIBUNWIND_HIDDEN -struct _Unwind_FunctionContext *__Unwind_SjLj_GetTopOfFunctionStack() { - return (struct _Unwind_FunctionContext *) - _pthread_getspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key); -} - -_LIBUNWIND_HIDDEN -void __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext *fc) { - _pthread_setspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key, fc); -} -#endif - - - - diff --git a/src/assembly.h b/src/assembly.h index f46a24d0eed..2df930214fa 100644 --- a/src/assembly.h +++ b/src/assembly.h @@ -16,7 +16,20 @@ #ifndef UNWIND_ASSEMBLY_H #define UNWIND_ASSEMBLY_H -#if defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__) +#if defined(__powerpc64__) +#define SEPARATOR ; +#define PPC64_OFFS_SRR0 0 +#define PPC64_OFFS_CR 272 +#define PPC64_OFFS_XER 280 +#define PPC64_OFFS_LR 288 +#define PPC64_OFFS_CTR 296 +#define PPC64_OFFS_VRSAVE 304 +#define PPC64_OFFS_FP 312 +#define PPC64_OFFS_V 824 +#ifdef _ARCH_PWR8 +#define PPC64_HAS_VMX +#endif +#elif defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__) #define SEPARATOR @ #elif defined(__arm64__) #define SEPARATOR %% @@ -24,40 +37,71 @@ #define SEPARATOR ; #endif -#if defined(__APPLE__) -#define HIDDEN_DIRECTIVE .private_extern -#else -#define HIDDEN_DIRECTIVE .hidden -#endif - #define GLUE2(a, b) a ## b #define GLUE(a, b) GLUE2(a, b) #define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name) #if defined(__APPLE__) + #define SYMBOL_IS_FUNC(name) +#define EXPORT_SYMBOL(name) +#define HIDDEN_SYMBOL(name) .private_extern name +#define NO_EXEC_STACK_DIRECTIVE + #elif defined(__ELF__) + #if defined(__arm__) #define SYMBOL_IS_FUNC(name) .type name,%function #else #define SYMBOL_IS_FUNC(name) .type name,@function #endif +#define EXPORT_SYMBOL(name) +#define HIDDEN_SYMBOL(name) .hidden name + +#if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \ + defined(__linux__) +#define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits #else +#define NO_EXEC_STACK_DIRECTIVE +#endif + +#elif defined(_WIN32) + #define SYMBOL_IS_FUNC(name) \ .def name SEPARATOR \ .scl 2 SEPARATOR \ .type 32 SEPARATOR \ .endef +#define EXPORT_SYMBOL2(name) \ + .section .drectve,"yn" SEPARATOR \ + .ascii "-export:", #name, "\0" SEPARATOR \ + .text +#if defined(_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS) +#define EXPORT_SYMBOL(name) +#else +#define EXPORT_SYMBOL(name) EXPORT_SYMBOL2(name) +#endif +#define HIDDEN_SYMBOL(name) + +#define NO_EXEC_STACK_DIRECTIVE + +#elif defined(__sparc__) + +#else + +#error Unsupported target + #endif #define DEFINE_LIBUNWIND_FUNCTION(name) \ .globl SYMBOL_NAME(name) SEPARATOR \ + EXPORT_SYMBOL(name) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ SYMBOL_NAME(name): #define DEFINE_LIBUNWIND_PRIVATE_FUNCTION(name) \ .globl SYMBOL_NAME(name) SEPARATOR \ - HIDDEN_DIRECTIVE SYMBOL_NAME(name) SEPARATOR \ + HIDDEN_SYMBOL(SYMBOL_NAME(name)) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ SYMBOL_NAME(name): diff --git a/src/config.h b/src/config.h index a50222f7c90..fc7fd646707 100644 --- a/src/config.h +++ b/src/config.h @@ -6,7 +6,7 @@ // Source Licenses. See LICENSE.TXT for details. // // -// Defines macros used within libuwind project. +// Defines macros used within libunwind project. // //===----------------------------------------------------------------------===// @@ -16,6 +16,7 @@ #include #include +#include #include // Define static_assert() unless already defined by compiler. @@ -31,51 +32,65 @@ // Platform specific configuration defines. #ifdef __APPLE__ #if defined(FOR_DYLD) - #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1 - #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 0 - #define _LIBUNWIND_SUPPORT_DWARF_INDEX 0 + #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND #else - #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1 + #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 - #define _LIBUNWIND_SUPPORT_DWARF_INDEX 0 + #endif +#elif defined(_WIN32) + #ifdef __SEH__ + #define _LIBUNWIND_SUPPORT_SEH_UNWIND 1 + #else + #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 #endif #else #if defined(__ARM_DWARF_EH__) || !defined(__arm__) - #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 0 #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 #define _LIBUNWIND_SUPPORT_DWARF_INDEX 1 - #else - #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 0 - #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 0 - #define _LIBUNWIND_SUPPORT_DWARF_INDEX 0 #endif #endif -// FIXME: these macros are not correct for COFF targets -#define _LIBUNWIND_EXPORT __attribute__((visibility("default"))) -#define _LIBUNWIND_HIDDEN __attribute__((visibility("hidden"))) - -#if (defined(__APPLE__) && defined(__arm__)) || defined(__USING_SJLJ_EXCEPTIONS__) -#define _LIBUNWIND_BUILD_SJLJ_APIS 1 +#if defined(_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS) + #define _LIBUNWIND_EXPORT + #define _LIBUNWIND_HIDDEN #else -#define _LIBUNWIND_BUILD_SJLJ_APIS 0 + #if !defined(__ELF__) && !defined(__MACH__) + #define _LIBUNWIND_EXPORT __declspec(dllexport) + #define _LIBUNWIND_HIDDEN + #else + #define _LIBUNWIND_EXPORT __attribute__((visibility("default"))) + #define _LIBUNWIND_HIDDEN __attribute__((visibility("hidden"))) + #endif #endif -#if defined(__i386__) || defined(__x86_64__) -#define _LIBUNWIND_SUPPORT_FRAME_APIS 1 -#else -#define _LIBUNWIND_SUPPORT_FRAME_APIS 0 +#if (defined(__APPLE__) && defined(__arm__)) || defined(__USING_SJLJ_EXCEPTIONS__) +#define _LIBUNWIND_BUILD_SJLJ_APIS +#endif + +#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__ppc64__) || defined(__powerpc64__) +#define _LIBUNWIND_SUPPORT_FRAME_APIS #endif #if defined(__i386__) || defined(__x86_64__) || \ + defined(__ppc__) || defined(__ppc64__) || defined(__powerpc64__) || \ (!defined(__APPLE__) && defined(__arm__)) || \ (defined(__arm64__) || defined(__aarch64__)) || \ - (defined(__APPLE__) && defined(__mips__)) -#define _LIBUNWIND_BUILD_ZERO_COST_APIS 1 -#else -#define _LIBUNWIND_BUILD_ZERO_COST_APIS 0 + defined(__mips__) +#if !defined(_LIBUNWIND_BUILD_SJLJ_APIS) +#define _LIBUNWIND_BUILD_ZERO_COST_APIS +#endif #endif +#if defined(__powerpc64__) && defined(_ARCH_PWR8) +#define PPC64_HAS_VMX +#endif + +#if defined(NDEBUG) && defined(_LIBUNWIND_IS_BAREMETAL) +#define _LIBUNWIND_ABORT(msg) \ + do { \ + abort(); \ + } while (0) +#else #define _LIBUNWIND_ABORT(msg) \ do { \ fprintf(stderr, "libunwind: %s %s:%d - %s\n", __func__, __FILE__, \ @@ -83,40 +98,65 @@ fflush(stderr); \ abort(); \ } while (0) -#define _LIBUNWIND_LOG(msg, ...) fprintf(stderr, "libuwind: " msg, __VA_ARGS__) +#endif + +#if defined(NDEBUG) && defined(_LIBUNWIND_IS_BAREMETAL) +#define _LIBUNWIND_LOG0(msg) +#define _LIBUNWIND_LOG(msg, ...) +#else +#define _LIBUNWIND_LOG0(msg) \ + fprintf(stderr, "libunwind: " msg "\n") +#define _LIBUNWIND_LOG(msg, ...) \ + fprintf(stderr, "libunwind: " msg "\n", __VA_ARGS__) +#endif + +#if defined(NDEBUG) + #define _LIBUNWIND_LOG_IF_FALSE(x) x +#else + #define _LIBUNWIND_LOG_IF_FALSE(x) \ + do { \ + bool _ret = x; \ + if (!_ret) \ + _LIBUNWIND_LOG("" #x " failed in %s", __FUNCTION__); \ + } while (0) +#endif // Macros that define away in non-Debug builds #ifdef NDEBUG #define _LIBUNWIND_DEBUG_LOG(msg, ...) #define _LIBUNWIND_TRACE_API(msg, ...) - #define _LIBUNWIND_TRACING_UNWINDING 0 + #define _LIBUNWIND_TRACING_UNWINDING (0) + #define _LIBUNWIND_TRACING_DWARF (0) #define _LIBUNWIND_TRACE_UNWINDING(msg, ...) - #define _LIBUNWIND_LOG_NON_ZERO(x) x + #define _LIBUNWIND_TRACE_DWARF(...) #else #ifdef __cplusplus extern "C" { #endif extern bool logAPIs(); extern bool logUnwinding(); + extern bool logDWARF(); #ifdef __cplusplus } #endif #define _LIBUNWIND_DEBUG_LOG(msg, ...) _LIBUNWIND_LOG(msg, __VA_ARGS__) - #define _LIBUNWIND_LOG_NON_ZERO(x) \ - do { \ - int _err = x; \ - if ( _err != 0 ) \ - _LIBUNWIND_LOG("" #x "=%d in %s", _err, __FUNCTION__); \ - } while (0) - #define _LIBUNWIND_TRACE_API(msg, ...) \ - do { \ - if ( logAPIs() ) _LIBUNWIND_LOG(msg, __VA_ARGS__); \ - } while(0) - #define _LIBUNWIND_TRACE_UNWINDING(msg, ...) \ - do { \ - if ( logUnwinding() ) _LIBUNWIND_LOG(msg, __VA_ARGS__); \ - } while(0) + #define _LIBUNWIND_TRACE_API(msg, ...) \ + do { \ + if (logAPIs()) \ + _LIBUNWIND_LOG(msg, __VA_ARGS__); \ + } while (0) #define _LIBUNWIND_TRACING_UNWINDING logUnwinding() + #define _LIBUNWIND_TRACING_DWARF logDWARF() + #define _LIBUNWIND_TRACE_UNWINDING(msg, ...) \ + do { \ + if (logUnwinding()) \ + _LIBUNWIND_LOG(msg, __VA_ARGS__); \ + } while (0) + #define _LIBUNWIND_TRACE_DWARF(...) \ + do { \ + if (logDWARF()) \ + fprintf(stderr, __VA_ARGS__); \ + } while (0) #endif #ifdef __cplusplus @@ -125,7 +165,7 @@ #if defined(_LIBUNWIND_IS_NATIVE_ONLY) # define COMP_OP == #else -# define COMP_OP < +# define COMP_OP <= #endif template struct check_fit { diff --git a/src/dwarf2.h b/src/dwarf2.h index 0dcd2ca99ba..58525eea044 100644 --- a/src/dwarf2.h +++ b/src/dwarf2.h @@ -49,7 +49,10 @@ enum { // GNU extensions DW_CFA_GNU_window_save = 0x2D, DW_CFA_GNU_args_size = 0x2E, - DW_CFA_GNU_negative_offset_extended = 0x2F + DW_CFA_GNU_negative_offset_extended = 0x2F, + + // AARCH64 extensions + DW_CFA_AARCH64_negate_ra_state = 0x2D }; diff --git a/src/libunwind.cpp b/src/libunwind.cpp index 95f2dc020dc..f4d71a1863b 100644 --- a/src/libunwind.cpp +++ b/src/libunwind.cpp @@ -1,4 +1,4 @@ -//===--------------------------- libuwind.cpp -----------------------------===// +//===--------------------------- libunwind.cpp ----------------------------===// // // The LLVM Compiler Infrastructure // @@ -24,6 +24,8 @@ #include +#if !defined(__USING_SJLJ_EXCEPTIONS__) +#include "AddressSpace.hpp" #include "UnwindCursor.hpp" using namespace libunwind; @@ -42,23 +44,31 @@ extern int unw_getcontext(unw_context_t *); /// unw_getcontext(). _LIBUNWIND_EXPORT int unw_init_local(unw_cursor_t *cursor, unw_context_t *context) { - _LIBUNWIND_TRACE_API("unw_init_local(cursor=%p, context=%p)\n", + _LIBUNWIND_TRACE_API("unw_init_local(cursor=%p, context=%p)", static_cast(cursor), static_cast(context)); #if defined(__i386__) # define REGISTER_KIND Registers_x86 #elif defined(__x86_64__) # define REGISTER_KIND Registers_x86_64 +#elif defined(__powerpc64__) +# define REGISTER_KIND Registers_ppc64 #elif defined(__ppc__) # define REGISTER_KIND Registers_ppc #elif defined(__aarch64__) # define REGISTER_KIND Registers_arm64 -#elif _LIBUNWIND_ARM_EHABI +#elif defined(__arm__) # define REGISTER_KIND Registers_arm #elif defined(__or1k__) # define REGISTER_KIND Registers_or1k +#elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32 +# define REGISTER_KIND Registers_mips_o32 +#elif defined(__mips64) +# define REGISTER_KIND Registers_mips_newabi #elif defined(__mips__) -# warning The MIPS architecture is not supported. +# warning The MIPS architecture is not supported with this ABI and environment! +#elif defined(__sparc__) +# define REGISTER_KIND Registers_sparc #else # error Architecture not supported #endif @@ -85,18 +95,18 @@ _LIBUNWIND_EXPORT int unw_init_remote_thread(unw_cursor_t *cursor, switch (as->cpuType) { case CPU_TYPE_I386: new ((void *)cursor) - UnwindCursor >, + UnwindCursor>, Registers_x86>(((unw_addr_space_i386 *)as)->oas, arg); break; case CPU_TYPE_X86_64: - new ((void *)cursor) UnwindCursor< - OtherAddressSpace >, Registers_x86_64>( - ((unw_addr_space_x86_64 *)as)->oas, arg); + new ((void *)cursor) + UnwindCursor>, + Registers_x86_64>(((unw_addr_space_x86_64 *)as)->oas, arg); break; case CPU_TYPE_POWERPC: new ((void *)cursor) - UnwindCursor >, Registers_ppc>( - ((unw_addr_space_ppc *)as)->oas, arg); + UnwindCursor>, + Registers_ppc>(((unw_addr_space_ppc *)as)->oas, arg); break; default: return UNW_EUNSPEC; @@ -157,7 +167,7 @@ _LIBUNWIND_EXPORT void unw_destroy_addr_space(unw_addr_space_t asp) { /// Get value of specified register at cursor position in stack frame. _LIBUNWIND_EXPORT int unw_get_reg(unw_cursor_t *cursor, unw_regnum_t regNum, unw_word_t *value) { - _LIBUNWIND_TRACE_API("unw_get_reg(cursor=%p, regNum=%d, &value=%p)\n", + _LIBUNWIND_TRACE_API("unw_get_reg(cursor=%p, regNum=%d, &value=%p)", static_cast(cursor), regNum, static_cast(value)); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; @@ -172,16 +182,28 @@ _LIBUNWIND_EXPORT int unw_get_reg(unw_cursor_t *cursor, unw_regnum_t regNum, /// Set value of specified register at cursor position in stack frame. _LIBUNWIND_EXPORT int unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum, unw_word_t value) { - _LIBUNWIND_TRACE_API("unw_set_reg(cursor=%p, regNum=%d, value=0x%llX)\n", - static_cast(cursor), regNum, (long long)value); + _LIBUNWIND_TRACE_API("unw_set_reg(cursor=%p, regNum=%d, value=0x%" PRIxPTR ")", + static_cast(cursor), regNum, value); typedef LocalAddressSpace::pint_t pint_t; AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; if (co->validReg(regNum)) { co->setReg(regNum, (pint_t)value); // specical case altering IP to re-find info (being called by personality // function) - if (regNum == UNW_REG_IP) + if (regNum == UNW_REG_IP) { + unw_proc_info_t info; + // First, get the FDE for the old location and then update it. + co->getInfo(&info); co->setInfoBasedOnIPRegister(false); + // If the original call expects stack adjustment, perform this now. + // Normal frame unwinding would have included the offset already in the + // CFA computation. + // Note: for PA-RISC and other platforms where the stack grows up, + // this should actually be - info.gp. LLVM doesn't currently support + // any such platforms and Clang doesn't export a macro for them. + if (info.gp) + co->setReg(UNW_REG_SP, co->getReg(UNW_REG_SP) + info.gp); + } return UNW_ESUCCESS; } return UNW_EBADREG; @@ -191,7 +213,7 @@ _LIBUNWIND_EXPORT int unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum, /// Get value of specified float register at cursor position in stack frame. _LIBUNWIND_EXPORT int unw_get_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum, unw_fpreg_t *value) { - _LIBUNWIND_TRACE_API("unw_get_fpreg(cursor=%p, regNum=%d, &value=%p)\n", + _LIBUNWIND_TRACE_API("unw_get_fpreg(cursor=%p, regNum=%d, &value=%p)", static_cast(cursor), regNum, static_cast(value)); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; @@ -206,11 +228,11 @@ _LIBUNWIND_EXPORT int unw_get_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum, /// Set value of specified float register at cursor position in stack frame. _LIBUNWIND_EXPORT int unw_set_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum, unw_fpreg_t value) { -#if _LIBUNWIND_ARM_EHABI - _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%llX)\n", +#if defined(_LIBUNWIND_ARM_EHABI) + _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%llX)", static_cast(cursor), regNum, value); #else - _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%g)\n", + _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%g)", static_cast(cursor), regNum, value); #endif AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; @@ -224,7 +246,7 @@ _LIBUNWIND_EXPORT int unw_set_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum, /// Move cursor to next frame. _LIBUNWIND_EXPORT int unw_step(unw_cursor_t *cursor) { - _LIBUNWIND_TRACE_API("unw_step(cursor=%p)\n", static_cast(cursor)); + _LIBUNWIND_TRACE_API("unw_step(cursor=%p)", static_cast(cursor)); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; return co->step(); } @@ -233,7 +255,7 @@ _LIBUNWIND_EXPORT int unw_step(unw_cursor_t *cursor) { /// Get unwind info at cursor position in stack frame. _LIBUNWIND_EXPORT int unw_get_proc_info(unw_cursor_t *cursor, unw_proc_info_t *info) { - _LIBUNWIND_TRACE_API("unw_get_proc_info(cursor=%p, &info=%p)\n", + _LIBUNWIND_TRACE_API("unw_get_proc_info(cursor=%p, &info=%p)", static_cast(cursor), static_cast(info)); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; co->getInfo(info); @@ -246,7 +268,7 @@ _LIBUNWIND_EXPORT int unw_get_proc_info(unw_cursor_t *cursor, /// Resume execution at cursor position (aka longjump). _LIBUNWIND_EXPORT int unw_resume(unw_cursor_t *cursor) { - _LIBUNWIND_TRACE_API("unw_resume(cursor=%p)\n", static_cast(cursor)); + _LIBUNWIND_TRACE_API("unw_resume(cursor=%p)", static_cast(cursor)); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; co->jumpto(); return UNW_EUNSPEC; @@ -256,7 +278,7 @@ _LIBUNWIND_EXPORT int unw_resume(unw_cursor_t *cursor) { /// Get name of function at cursor position in stack frame. _LIBUNWIND_EXPORT int unw_get_proc_name(unw_cursor_t *cursor, char *buf, size_t bufLen, unw_word_t *offset) { - _LIBUNWIND_TRACE_API("unw_get_proc_name(cursor=%p, &buf=%p, bufLen=%lu)\n", + _LIBUNWIND_TRACE_API("unw_get_proc_name(cursor=%p, &buf=%p, bufLen=%lu)", static_cast(cursor), static_cast(buf), static_cast(bufLen)); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; @@ -269,7 +291,7 @@ _LIBUNWIND_EXPORT int unw_get_proc_name(unw_cursor_t *cursor, char *buf, /// Checks if a register is a floating-point register. _LIBUNWIND_EXPORT int unw_is_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum) { - _LIBUNWIND_TRACE_API("unw_is_fpreg(cursor=%p, regNum=%d)\n", + _LIBUNWIND_TRACE_API("unw_is_fpreg(cursor=%p, regNum=%d)", static_cast(cursor), regNum); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; return co->validFloatReg(regNum); @@ -279,7 +301,7 @@ _LIBUNWIND_EXPORT int unw_is_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum) { /// Checks if a register is a floating-point register. _LIBUNWIND_EXPORT const char *unw_regname(unw_cursor_t *cursor, unw_regnum_t regNum) { - _LIBUNWIND_TRACE_API("unw_regname(cursor=%p, regNum=%d)\n", + _LIBUNWIND_TRACE_API("unw_regname(cursor=%p, regNum=%d)", static_cast(cursor), regNum); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; return co->getRegisterName(regNum); @@ -288,7 +310,7 @@ _LIBUNWIND_EXPORT const char *unw_regname(unw_cursor_t *cursor, /// Checks if current frame is signal trampoline. _LIBUNWIND_EXPORT int unw_is_signal_frame(unw_cursor_t *cursor) { - _LIBUNWIND_TRACE_API("unw_is_signal_frame(cursor=%p)\n", + _LIBUNWIND_TRACE_API("unw_is_signal_frame(cursor=%p)", static_cast(cursor)); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; return co->isSignalFrame(); @@ -297,7 +319,7 @@ _LIBUNWIND_EXPORT int unw_is_signal_frame(unw_cursor_t *cursor) { #ifdef __arm__ // Save VFP registers d0-d15 using FSTMIADX instead of FSTMIADD _LIBUNWIND_EXPORT void unw_save_vfp_as_X(unw_cursor_t *cursor) { - _LIBUNWIND_TRACE_API("unw_fpreg_save_vfp_as_X(cursor=%p)\n", + _LIBUNWIND_TRACE_API("unw_fpreg_save_vfp_as_X(cursor=%p)", static_cast(cursor)); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; return co->saveVFPAsX(); @@ -305,11 +327,11 @@ _LIBUNWIND_EXPORT void unw_save_vfp_as_X(unw_cursor_t *cursor) { #endif -#if _LIBUNWIND_SUPPORT_DWARF_UNWIND -/// SPI: walks cached dwarf entries +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) +/// SPI: walks cached DWARF entries _LIBUNWIND_EXPORT void unw_iterate_dwarf_unwind_cache(void (*func)( unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) { - _LIBUNWIND_TRACE_API("unw_iterate_dwarf_unwind_cache(func=%p)\n", + _LIBUNWIND_TRACE_API("unw_iterate_dwarf_unwind_cache(func=%p)", reinterpret_cast(func)); DwarfFDECache::iterateCacheEntries(func); } @@ -339,7 +361,8 @@ void _unw_remove_dynamic_fde(unw_word_t fde) { // fde is own mh_group DwarfFDECache::removeAllIn((LocalAddressSpace::pint_t)fde); } -#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND +#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) +#endif // !defined(__USING_SJLJ_EXCEPTIONS__) @@ -371,5 +394,17 @@ bool logUnwinding() { return log; } +_LIBUNWIND_HIDDEN +bool logDWARF() { + // do manual lock to avoid use of _cxa_guard_acquire or initializers + static bool checked = false; + static bool log = false; + if (!checked) { + log = (getenv("LIBUNWIND_PRINT_DWARF") != NULL); + checked = true; + } + return log; +} + #endif // NDEBUG diff --git a/src/libunwind_ext.h b/src/libunwind_ext.h index 72dbf5851a8..ec645a84673 100644 --- a/src/libunwind_ext.h +++ b/src/libunwind_ext.h @@ -33,7 +33,7 @@ extern void unw_iterate_dwarf_unwind_cache(void (*func)(unw_word_t ip_start, extern void _unw_add_dynamic_fde(unw_word_t fde); extern void _unw_remove_dynamic_fde(unw_word_t fde); -#if _LIBUNWIND_ARM_EHABI +#if defined(_LIBUNWIND_ARM_EHABI) extern const uint32_t* decode_eht_entry(const uint32_t*, size_t*, size_t*); extern _Unwind_Reason_Code _Unwind_VRS_Interpret(_Unwind_Context *context, const uint32_t *data, diff --git a/src/unwind_ext.h b/src/unwind_ext.h deleted file mode 100644 index c40ce6a1610..00000000000 --- a/src/unwind_ext.h +++ /dev/null @@ -1,37 +0,0 @@ -//===-------------------------- unwind_ext.h ------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -// -// Extensions to unwind API. -// -//===----------------------------------------------------------------------===// - -#ifndef __UNWIND_EXT__ -#define __UNWIND_EXT__ - -#include "unwind.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// These platform specific functions to get and set the top context are -// implemented elsewhere. - -extern struct _Unwind_FunctionContext * -__Unwind_SjLj_GetTopOfFunctionStack(); - -extern void -__Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext *fc); - -#ifdef __cplusplus -} -#endif - -#endif // __UNWIND_EXT__ - - From 758a81d16ef3cd307311c130fa34ea149f40149a Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Fri, 8 Mar 2019 22:45:03 +0000 Subject: [PATCH 02/18] Vendor import of LLVM libunwind release_80 branch r355677: https://llvm.org/svn/llvm-project/libunwind/branches/release_80@355677 --- src/AddressSpace.hpp | 6 +++--- src/EHHeaderParser.hpp | 16 +++++++++++----- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/AddressSpace.hpp b/src/AddressSpace.hpp index 30ad35995ae..49bb360d794 100644 --- a/src/AddressSpace.hpp +++ b/src/AddressSpace.hpp @@ -534,11 +534,11 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, #endif cbdata->sects->dwarf_index_section = eh_frame_hdr_start; cbdata->sects->dwarf_index_section_length = phdr->p_memsz; - EHHeaderParser::decodeEHHdr( + found_hdr = EHHeaderParser::decodeEHHdr( *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz, hdrInfo); - cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr; - found_hdr = true; + if (found_hdr) + cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr; } } diff --git a/src/EHHeaderParser.hpp b/src/EHHeaderParser.hpp index 9bdaf5505ff..6b3e7dead86 100644 --- a/src/EHHeaderParser.hpp +++ b/src/EHHeaderParser.hpp @@ -36,7 +36,7 @@ template class EHHeaderParser { uint8_t table_enc; }; - static void decodeEHHdr(A &addressSpace, pint_t ehHdrStart, pint_t ehHdrEnd, + static bool decodeEHHdr(A &addressSpace, pint_t ehHdrStart, pint_t ehHdrEnd, EHHeaderInfo &ehHdrInfo); static bool findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart, uint32_t sectionLength, @@ -53,12 +53,14 @@ template class EHHeaderParser { }; template -void EHHeaderParser::decodeEHHdr(A &addressSpace, pint_t ehHdrStart, +bool EHHeaderParser::decodeEHHdr(A &addressSpace, pint_t ehHdrStart, pint_t ehHdrEnd, EHHeaderInfo &ehHdrInfo) { pint_t p = ehHdrStart; uint8_t version = addressSpace.get8(p++); - if (version != 1) - _LIBUNWIND_ABORT("Unsupported .eh_frame_hdr version"); + if (version != 1) { + _LIBUNWIND_LOG0("Unsupported .eh_frame_hdr version"); + return false; + } uint8_t eh_frame_ptr_enc = addressSpace.get8(p++); uint8_t fde_count_enc = addressSpace.get8(p++); @@ -71,6 +73,8 @@ void EHHeaderParser::decodeEHHdr(A &addressSpace, pint_t ehHdrStart, ? 0 : addressSpace.getEncodedP(p, ehHdrEnd, fde_count_enc, ehHdrStart); ehHdrInfo.table = p; + + return true; } template @@ -102,7 +106,9 @@ bool EHHeaderParser::findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart, pint_t ehHdrEnd = ehHdrStart + sectionLength; EHHeaderParser::EHHeaderInfo hdrInfo; - EHHeaderParser::decodeEHHdr(addressSpace, ehHdrStart, ehHdrEnd, hdrInfo); + if (!EHHeaderParser::decodeEHHdr(addressSpace, ehHdrStart, ehHdrEnd, + hdrInfo)) + return false; size_t tableEntrySize = getTableEntrySize(hdrInfo.table_enc); pint_t tableEntry; From 6daa4a40796a01decdfa4bfe618f49cb503a1153 Mon Sep 17 00:00:00 2001 From: Ian Lepore Date: Mon, 11 Mar 2019 03:07:05 +0000 Subject: [PATCH 03/18] Mark the imx_spi device busy while transfers are in progress, so that the module can't be unloaded while interrupts are pending. --- sys/arm/freescale/imx/imx_spi.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sys/arm/freescale/imx/imx_spi.c b/sys/arm/freescale/imx/imx_spi.c index b6239b20a9c..21add56cef7 100644 --- a/sys/arm/freescale/imx/imx_spi.c +++ b/sys/arm/freescale/imx/imx_spi.c @@ -424,6 +424,7 @@ spi_transfer(device_t dev, device_t child, struct spi_command *cmd) } mtx_lock(&sc->mtx); + device_busy(sc->dev); if (sc->debug >= 1) { device_printf(sc->dev, @@ -448,6 +449,7 @@ spi_transfer(device_t dev, device_t child, struct spi_command *cmd) spi_set_chipsel(sc, cs, false); WR4(sc, ECSPI_CTLREG, 0); + device_unbusy(sc->dev); mtx_unlock(&sc->mtx); return (err); @@ -468,11 +470,11 @@ static int spi_detach(device_t dev) { struct spi_softc *sc = device_get_softc(dev); - int idx; + int error, idx; - mtx_lock(&sc->mtx); + if ((error = bus_generic_detach(sc->dev)) != 0) + return (error); - bus_generic_detach(sc->dev); if (sc->spibus != NULL) device_delete_child(dev, sc->spibus); @@ -488,7 +490,6 @@ spi_detach(device_t dev) if (sc->memres != NULL) bus_release_resource(sc->dev, SYS_RES_MEMORY, 0, sc->memres); - mtx_unlock(&sc->mtx); mtx_destroy(&sc->mtx); return (0); From 589526906c3cbae5f1fa38f1b89d614ffe8b4643 Mon Sep 17 00:00:00 2001 From: Andriy Voskoboinyk Date: Mon, 11 Mar 2019 08:30:29 +0000 Subject: [PATCH 04/18] iwm(4): use correct channel list source for Intel 3168 Intel 3168 uses another EEPROM section to store channel flags; port missing bits from iwlwifi to make it work. PR: 230750, 236235 Tested by: Bert JW Regeer MFC after: 3 days --- sys/dev/iwm/if_iwm.c | 8 +++++--- sys/dev/iwm/if_iwm_7000.c | 1 + sys/dev/iwm/if_iwm_config.h | 15 +++++++++++++++ sys/dev/iwm/if_iwmreg.h | 1 + 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/sys/dev/iwm/if_iwm.c b/sys/dev/iwm/if_iwm.c index b87085244a7..b32f728ab7c 100644 --- a/sys/dev/iwm/if_iwm.c +++ b/sys/dev/iwm/if_iwm.c @@ -2211,7 +2211,8 @@ iwm_parse_nvm_data(struct iwm_softc *sc, } if (sc->cfg->device_family == IWM_DEVICE_FAMILY_7000) { - memcpy(data->nvm_ch_flags, &nvm_sw[IWM_NVM_CHANNELS], + memcpy(data->nvm_ch_flags, sc->cfg->nvm_type == IWM_NVM_SDP ? + ®ulatory[0] : &nvm_sw[IWM_NVM_CHANNELS], IWM_NUM_CHANNELS * sizeof(uint16_t)); } else { memcpy(data->nvm_ch_flags, ®ulatory[IWM_NVM_CHANNELS_8000], @@ -2271,8 +2272,9 @@ iwm_parse_nvm_sections(struct iwm_softc *sc, struct iwm_nvm_section *sections) sw = (const uint16_t *)sections[IWM_NVM_SECTION_TYPE_SW].data; calib = (const uint16_t *) sections[IWM_NVM_SECTION_TYPE_CALIBRATION].data; - regulatory = (const uint16_t *) - sections[IWM_NVM_SECTION_TYPE_REGULATORY].data; + regulatory = sc->cfg->nvm_type == IWM_NVM_SDP ? + (const uint16_t *)sections[IWM_NVM_SECTION_TYPE_REGULATORY_SDP].data : + (const uint16_t *)sections[IWM_NVM_SECTION_TYPE_REGULATORY].data; mac_override = (const uint16_t *) sections[IWM_NVM_SECTION_TYPE_MAC_OVERRIDE].data; phy_sku = (const uint16_t *)sections[IWM_NVM_SECTION_TYPE_PHY_SKU].data; diff --git a/sys/dev/iwm/if_iwm_7000.c b/sys/dev/iwm/if_iwm_7000.c index beb2a2e5a3b..3da0cac2b42 100644 --- a/sys/dev/iwm/if_iwm_7000.c +++ b/sys/dev/iwm/if_iwm_7000.c @@ -119,6 +119,7 @@ const struct iwm_cfg iwm3168_cfg = { .fw_name = IWM3168_FW, IWM_DEVICE_7000_COMMON, .host_interrupt_operation_mode = 0, + .nvm_type = IWM_NVM_SDP, }; const struct iwm_cfg iwm7265_cfg = { diff --git a/sys/dev/iwm/if_iwm_config.h b/sys/dev/iwm/if_iwm_config.h index 4d897973968..4768a16f526 100644 --- a/sys/dev/iwm/if_iwm_config.h +++ b/sys/dev/iwm/if_iwm_config.h @@ -104,6 +104,19 @@ static inline uint8_t num_of_ant(uint8_t mask) #define IWM_OTP_LOW_IMAGE_SIZE_FAMILY_8000 (32 * 512 * sizeof(uint16_t)) /* 32 KB */ #define IWM_OTP_LOW_IMAGE_SIZE_FAMILY_9000 IWM_OTP_LOW_IMAGE_SIZE_FAMILY_8000 + +/** + * enum iwl_nvm_type - nvm formats + * @IWM_NVM: the regular format + * @IWM_NVM_EXT: extended NVM format + * @IWM_NVM_SDP: NVM format used by 3168 series + */ +enum iwm_nvm_type { + IWM_NVM, + IWM_NVM_EXT, + IWM_NVM_SDP, +}; + /** * struct iwm_cfg * @name: Official name of the device @@ -113,6 +126,7 @@ static inline uint8_t num_of_ant(uint8_t mask) * @nvm_hw_section_num: the ID of the HW NVM section * @apmg_wake_up_wa: should the MAC access REQ be asserted when a command * is in flight. This is due to a HW bug in 7260, 3160 and 7265. + * @nvm_type: see &enum iwl_nvm_type */ struct iwm_cfg { const char *name; @@ -122,6 +136,7 @@ struct iwm_cfg { int host_interrupt_operation_mode; uint8_t nvm_hw_section_num; int apmg_wake_up_wa; + enum iwm_nvm_type nvm_type; }; /* diff --git a/sys/dev/iwm/if_iwmreg.h b/sys/dev/iwm/if_iwmreg.h index c7afcb35ce1..67f1bbff0f0 100644 --- a/sys/dev/iwm/if_iwmreg.h +++ b/sys/dev/iwm/if_iwmreg.h @@ -2032,6 +2032,7 @@ enum { IWM_NVM_SECTION_TYPE_REGULATORY = 3, IWM_NVM_SECTION_TYPE_CALIBRATION = 4, IWM_NVM_SECTION_TYPE_PRODUCTION = 5, + IWM_NVM_SECTION_TYPE_REGULATORY_SDP = 8, IWM_NVM_SECTION_TYPE_MAC_OVERRIDE = 11, IWM_NVM_SECTION_TYPE_PHY_SKU = 12, IWM_NVM_MAX_NUM_SECTIONS = 13, From d76227959a51c4879df40688bb861f707516281b Mon Sep 17 00:00:00 2001 From: "Andrey V. Elsukov" Date: Mon, 11 Mar 2019 10:33:32 +0000 Subject: [PATCH 05/18] Add NULL pointer check to nat64_output(). It is possible, that a processed packet was originated by local host, in this case m->m_pkthdr.rcvif is NULL. Check and set it to V_loif to avoid NULL pointer dereference in IP input code, since it is expected that packet has valid receiving interface when netisr processes it. Obtained from: Yandex LLC MFC after: 1 week Sponsored by: Yandex LLC --- sys/netpfil/ipfw/nat64/nat64_translate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sys/netpfil/ipfw/nat64/nat64_translate.c b/sys/netpfil/ipfw/nat64/nat64_translate.c index 4c2301e70e3..db26d7d3f87 100644 --- a/sys/netpfil/ipfw/nat64/nat64_translate.c +++ b/sys/netpfil/ipfw/nat64/nat64_translate.c @@ -219,6 +219,8 @@ nat64_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, } if (logdata != NULL) nat64_log(logdata, m, af); + if (m->m_pkthdr.rcvif == NULL) + m->m_pkthdr.rcvif = V_loif; ret = netisr_queue(ret, m); if (ret != 0) NAT64STAT_INC(stats, oerrors); From ca0f03e808edc4f54bfcb16b46532604ecad83a8 Mon Sep 17 00:00:00 2001 From: "Andrey V. Elsukov" Date: Mon, 11 Mar 2019 10:42:09 +0000 Subject: [PATCH 06/18] Add IP_FW_NAT64 to codes that ipfw_chk() can return. It will be used by upcoming NAT64 changes. We use separate code to avoid propogating EACCES error code to user level applications when NAT64 consumes a packet. Obtained from: Yandex LLC MFC after: 1 week Sponsored by: Yandex LLC --- sys/netpfil/ipfw/ip_fw_pfil.c | 4 ++++ sys/netpfil/ipfw/ip_fw_private.h | 1 + 2 files changed, 5 insertions(+) diff --git a/sys/netpfil/ipfw/ip_fw_pfil.c b/sys/netpfil/ipfw/ip_fw_pfil.c index 25726bd4636..440d73e3f1f 100644 --- a/sys/netpfil/ipfw/ip_fw_pfil.c +++ b/sys/netpfil/ipfw/ip_fw_pfil.c @@ -313,6 +313,10 @@ ipfw_check_packet(struct mbuf **m0, struct ifnet *ifp, int dir, case IP_FW_REASS: goto again; /* continue with packet */ + case IP_FW_NAT64: + ret = PFIL_CONSUMED; + break; + default: KASSERT(0, ("%s: unknown retval", __func__)); } diff --git a/sys/netpfil/ipfw/ip_fw_private.h b/sys/netpfil/ipfw/ip_fw_private.h index e0e24122168..c01fc57c3b4 100644 --- a/sys/netpfil/ipfw/ip_fw_private.h +++ b/sys/netpfil/ipfw/ip_fw_private.h @@ -61,6 +61,7 @@ enum { IP_FW_NGTEE, IP_FW_NAT, IP_FW_REASS, + IP_FW_NAT64, }; /* From c65b552f895bcb8ea931da6304108a3e008ff669 Mon Sep 17 00:00:00 2001 From: Kurt Lidl Date: Mon, 11 Mar 2019 13:33:03 +0000 Subject: [PATCH 07/18] Remove an unneeded 'tail -n 1' from a pipeline When piping to awk, it's almost always an anti-pattern to use 'grep' first. When not in a pipeline, sometimes it is faster to use tail, as awk must process all the lines in the input stream, and won't 'seek'. In a pipeline, both grep and awk must process all lines, so we might as well skip the extra process creation for tail and just use awk for all the processing. Reviewed by: jilles MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D19441 --- libexec/rc/rc.d/growfs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libexec/rc/rc.d/growfs b/libexec/rc/rc.d/growfs index 98f1d9b649c..039813c8f3e 100755 --- a/libexec/rc/rc.d/growfs +++ b/libexec/rc/rc.d/growfs @@ -57,7 +57,7 @@ growfs_start () ;; zfs) pool=${FSDEV%%/*} - rootdev=$(zpool list -v $pool | tail -n 1 | awk '{ print $1 }') + rootdev=$(zpool list -v $pool | awk 'END { print $1 }') ;; *) echo "Don't know how to grow root filesystem type: $FSTYPE" From 6f9dbc0e6ec465793f19a48620e1205cc1eec2be Mon Sep 17 00:00:00 2001 From: "Kenneth D. Merry" Date: Mon, 11 Mar 2019 14:21:14 +0000 Subject: [PATCH 08/18] Fix CRN resets in the isp(4) driver in certain situations. The Command Reference Number (CRN) is part of the FC-Tape features that we enable when talking to tape drives. It starts at 1, and goes to 255 and wraps around to 1. There are a number of reset type conditions that result in the CRN getting reset to 1. These are detailed in section 4.10 (table 8) of the FCP-4r02b specification. One of the conditions is when a PRLI (Process Login) is sent by the initiator, and the Establish Image Pair bit is set in Word 0 of the PRLI. Previously, the isp(4) driver core sent a notification via isp_async() that the target had changed or stayed in place, but there was no indication of whether a PRLI was sent and whether the Establish Image Pair bit was set. The result of this was that in some situations, notably switching back and forth between a direct connection and a switch connection to a tape drive, the isp(4) driver would fail to reset the CRN in situations that require it according to the spec. When the CRN isn't reset in a situation that requires it, the tape drive then rejects every subsequent command that is sent to the drive. It is assuming that the commands are being sent out of order. So, modify the isp(4) driver to include Word 0 of the PRLI command when it sends isp_async() notifications of target changes. Look at the Establish Image Pair bit, and reset the CRN if that bit is set. With this change, I am able to switch a tape drive back and forth between a direct connection and a switch connection, and the isp(4) driver resets the CRN when it should. sys/dev/isp_stds.h: Add bit definitions for PRLI Word 0. sys/dev/ispmbox.h: Add PRLI Word 0 to the port database type, isp_pdb_t. sys/dev/ispvar.h Add PRLI Word 0 to fcportdb_t. sys/dev/isp.c: Populate the new prli_word0 parameter in the port database. In isp_pdb_add_update(), add a check to see if the Establish Image Pair bit is set in PRLI Word 0. If it is, then that is an additional reason to create a change notification. sys/dev/isp_freebsd.c: In isp_async(), if the device changed or stayed, look at PRLI Word 0 to see if the Establish Image Pair bit is set. If it is, reset the CRN if we haven't already. MFC after: 1 week Sponsored by: Spectra Logic Differential Revision: https://reviews.freebsd.org/D19472 --- sys/dev/isp/isp.c | 7 ++++++- sys/dev/isp/isp_freebsd.c | 18 ++++++++++++++++-- sys/dev/isp/isp_stds.h | 8 ++++++++ sys/dev/isp/ispmbox.h | 1 + sys/dev/isp/ispvar.h | 5 +++++ 5 files changed, 36 insertions(+), 3 deletions(-) diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c index d4f88151a95..77f5045783e 100644 --- a/sys/dev/isp/isp.c +++ b/sys/dev/isp/isp.c @@ -2791,6 +2791,7 @@ isp_getpdb(ispsoftc_t *isp, int chan, uint16_t id, isp_pdb_t *pdb) if (IS_24XX(isp)) { isp_get_pdb_24xx(isp, isp->isp_iocb, &un.bill); pdb->handle = un.bill.pdb_handle; + pdb->prli_word0 = un.bill.pdb_prli_svc0; pdb->prli_word3 = un.bill.pdb_prli_svc3; pdb->portid = BITS2WORD_24XX(un.bill.pdb_portid_bits); ISP_MEMCPY(pdb->portname, un.bill.pdb_portname, 8); @@ -2807,6 +2808,7 @@ isp_getpdb(ispsoftc_t *isp, int chan, uint16_t id, isp_pdb_t *pdb) } else { isp_get_pdb_21xx(isp, isp->isp_iocb, &un.fred); pdb->handle = un.fred.pdb_loopid; + pdb->prli_word0 = un.fred.pdb_prli_svc0; pdb->prli_word3 = un.fred.pdb_prli_svc3; pdb->portid = BITS2WORD(un.fred.pdb_portid_bits); ISP_MEMCPY(pdb->portname, un.fred.pdb_portname, 8); @@ -3196,6 +3198,7 @@ isp_pdb_sync(ispsoftc_t *isp, int chan) lp->state = FC_PORTDB_STATE_VALID; isp_async(isp, ISPASYNC_DEV_CHANGED, chan, lp); lp->portid = lp->new_portid; + lp->prli_word0 = lp->new_prli_word0; lp->prli_word3 = lp->new_prli_word3; break; case FC_PORTDB_STATE_VALID: @@ -3247,7 +3250,8 @@ isp_pdb_add_update(ispsoftc_t *isp, int chan, isp_pdb_t *pdb) /* Old device, nothing new. */ if (lp->portid == pdb->portid && lp->handle == pdb->handle && - lp->prli_word3 == pdb->prli_word3) { + lp->prli_word3 == pdb->prli_word3 && + ((pdb->prli_word0 & PRLI_WD0_EST_IMAGE_PAIR) == 0)) { if (lp->state != FC_PORTDB_STATE_NEW) lp->state = FC_PORTDB_STATE_VALID; isp_prt(isp, ISP_LOG_SANCFG, @@ -3260,6 +3264,7 @@ isp_pdb_add_update(ispsoftc_t *isp, int chan, isp_pdb_t *pdb) lp->state = FC_PORTDB_STATE_CHANGED; lp->handle = pdb->handle; lp->new_portid = pdb->portid; + lp->new_prli_word0 = pdb->prli_word0; lp->new_prli_word3 = pdb->prli_word3; isp_prt(isp, ISP_LOG_SANCFG, "Chan %d Port 0x%06x@0x%04x is changed", diff --git a/sys/dev/isp/isp_freebsd.c b/sys/dev/isp/isp_freebsd.c index 693df8f6646..df671d123d2 100644 --- a/sys/dev/isp/isp_freebsd.c +++ b/sys/dev/isp/isp_freebsd.c @@ -3742,6 +3742,10 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...) break; case ISPASYNC_DEV_CHANGED: case ISPASYNC_DEV_STAYED: + { + int crn_reset_done; + + crn_reset_done = 0; va_start(ap, cmd); bus = va_arg(ap, int); lp = va_arg(ap, fcportdb_t *); @@ -3759,13 +3763,17 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...) (lp->new_prli_word3 & PRLI_WD3_TARGET_FUNCTION))) { lp->is_target = !lp->is_target; if (lp->is_target) { - if (cmd == ISPASYNC_DEV_CHANGED) + if (cmd == ISPASYNC_DEV_CHANGED) { isp_fcp_reset_crn(isp, bus, tgt, /*tgt_set*/ 1); + crn_reset_done = 1; + } isp_make_here(isp, lp, bus, tgt); } else { isp_make_gone(isp, lp, bus, tgt); - if (cmd == ISPASYNC_DEV_CHANGED) + if (cmd == ISPASYNC_DEV_CHANGED) { isp_fcp_reset_crn(isp, bus, tgt, /*tgt_set*/ 1); + crn_reset_done = 1; + } } } if (lp->is_initiator != @@ -3780,7 +3788,13 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...) adc->arrived = lp->is_initiator; xpt_async(AC_CONTRACT, fc->path, &ac); } + + if ((lp->new_prli_word0 & PRLI_WD0_EST_IMAGE_PAIR) && + (crn_reset_done == 0)) + isp_fcp_reset_crn(isp, bus, tgt, /*tgt_set*/ 1); + break; + } case ISPASYNC_DEV_GONE: va_start(ap, cmd); bus = va_arg(ap, int); diff --git a/sys/dev/isp/isp_stds.h b/sys/dev/isp/isp_stds.h index c095901da4b..197962f2cee 100644 --- a/sys/dev/isp/isp_stds.h +++ b/sys/dev/isp/isp_stds.h @@ -283,6 +283,14 @@ typedef struct { #define ADISC 0x52 #define RNC 0x53 +/* + * PRLI Word 0 definitions + * FPC4-r02b January, 2011 + */ +#define PRLI_WD0_TYPE_MASK 0xff000000 +#define PRLI_WD0_TC_EXT_MASK 0x00ff0000 +#define PRLI_WD0_EST_IMAGE_PAIR (1 << 13) + /* * PRLI Word 3 definitions * FPC4-r02b January, 2011 diff --git a/sys/dev/isp/ispmbox.h b/sys/dev/isp/ispmbox.h index 887b6115822..0b46e1cffc2 100644 --- a/sys/dev/isp/ispmbox.h +++ b/sys/dev/isp/ispmbox.h @@ -1384,6 +1384,7 @@ typedef struct { */ typedef struct { uint16_t handle; + uint16_t prli_word0; uint16_t prli_word3; uint32_t : 8, portid : 24; diff --git a/sys/dev/isp/ispvar.h b/sys/dev/isp/ispvar.h index 1e963916ca1..45513a3b687 100644 --- a/sys/dev/isp/ispvar.h +++ b/sys/dev/isp/ispvar.h @@ -381,6 +381,9 @@ typedef struct { uint16_t handle; /* + * PRLI word 0 contains the Establish Image Pair bit, which is + * important for knowing when to reset the CRN. + * * PRLI word 3 parameters contains role as well as other things. * * The state is the current state of this entry. @@ -392,7 +395,9 @@ typedef struct { * Portid is obvious, as are node && port WWNs. The new_role and * new_portid is for when we are pending a change. */ + uint16_t prli_word0; /* PRLI parameters */ uint16_t prli_word3; /* PRLI parameters */ + uint16_t new_prli_word0; /* Incoming new PRLI parameters */ uint16_t new_prli_word3; /* Incoming new PRLI parameters */ uint16_t : 12, probational : 1, From 2fb6802f2754f96a67d0310444e4d74caede0db0 Mon Sep 17 00:00:00 2001 From: David Bright Date: Mon, 11 Mar 2019 14:26:45 +0000 Subject: [PATCH 09/18] Fix a scribbler in the PMS driver. The ESGL bit was left uninitialized when executing the REPORT LUNS ioctl. This could allow a zeroed data buffer to be treated as a scatter/gather list. The firmware would eventually walk past the end of the data buffer, potentially find what looked like a valid address/length pair, and write the result to semi-random memory. Obtained from: Dell EMC Isilon MFC after: 1 week Sponsored by: Dell EMC Isilon Differential Revision: https://reviews.freebsd.org/D19398 --- sys/dev/pms/RefTisa/tisa/sassata/sas/ini/itdio.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sys/dev/pms/RefTisa/tisa/sassata/sas/ini/itdio.c b/sys/dev/pms/RefTisa/tisa/sassata/sas/ini/itdio.c index c7d0ca08564..15b83e9e221 100644 --- a/sys/dev/pms/RefTisa/tisa/sassata/sas/ini/itdio.c +++ b/sys/dev/pms/RefTisa/tisa/sassata/sas/ini/itdio.c @@ -1874,7 +1874,9 @@ tiNumOfLunIOCTLreq( agSSPFrame->dataLength = REPORT_LUN_LEN; agSSPFrame->agSgl.len = sizeof(agsaSSPCmdInfoUnit_t); - + agSSPFrame->agSgl.extReserved = 0; + CLEAR_ESGL_EXTEND(agSSPFrame->agSgl.extReserved); + status = saSSPStart(agRoot, agIORequest, 0, agDevHandle, agRequestType,agSASRequestBody,agNULL, &ossaSSPIoctlCompleted); if(status != AGSA_RC_SUCCESS) From 6f490688f521bfdc8944c050767453cdc54c7ae2 Mon Sep 17 00:00:00 2001 From: Hans Petter Selasky Date: Mon, 11 Mar 2019 14:29:50 +0000 Subject: [PATCH 10/18] Improve support for switching to and from command polling mode in mlx4core. Make sure the enter and leave polling routines can be called multiple times with same setting. Ignore setting polling or event mode twice. This fixes a deadlock during shutdown if polling mode was already selected. MFC after: 1 week Sponsored by: Mellanox Technologies --- sys/dev/mlx4/mlx4_core/mlx4_cmd.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/sys/dev/mlx4/mlx4_core/mlx4_cmd.c b/sys/dev/mlx4/mlx4_core/mlx4_cmd.c index 36f73822607..39a4064e3ff 100644 --- a/sys/dev/mlx4/mlx4_core/mlx4_cmd.c +++ b/sys/dev/mlx4/mlx4_core/mlx4_cmd.c @@ -2490,6 +2490,7 @@ int mlx4_cmd_init(struct mlx4_dev *dev) init_rwsem(&priv->cmd.switch_sem); mutex_init(&priv->cmd.slave_cmd_mutex); sema_init(&priv->cmd.poll_sem, 1); + sema_init(&priv->cmd.event_sem, 0); priv->cmd.use_events = 0; priv->cmd.toggle = 1; priv->cmd.initialized = 1; @@ -2617,7 +2618,9 @@ int mlx4_cmd_use_events(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); int i; - int err = 0; + + if (priv->cmd.use_events != 0) + return 0; priv->cmd.context = kmalloc(priv->cmd.max_cmds * sizeof (struct mlx4_cmd_context), @@ -2639,7 +2642,8 @@ int mlx4_cmd_use_events(struct mlx4_dev *dev) priv->cmd.context[priv->cmd.max_cmds - 1].next = -1; priv->cmd.free_head = 0; - sema_init(&priv->cmd.event_sem, priv->cmd.max_cmds); + for (i = 0; i != priv->cmd.max_cmds; i++) + up(&priv->cmd.event_sem); for (priv->cmd.token_mask = 1; priv->cmd.token_mask < priv->cmd.max_cmds; @@ -2651,7 +2655,7 @@ int mlx4_cmd_use_events(struct mlx4_dev *dev) priv->cmd.use_events = 1; up_write(&priv->cmd.switch_sem); - return err; + return 0; } /* @@ -2662,6 +2666,9 @@ void mlx4_cmd_use_polling(struct mlx4_dev *dev) struct mlx4_priv *priv = mlx4_priv(dev); int i; + if (priv->cmd.use_events == 0) + return; + down_write(&priv->cmd.switch_sem); priv->cmd.use_events = 0; @@ -2669,6 +2676,7 @@ void mlx4_cmd_use_polling(struct mlx4_dev *dev) down(&priv->cmd.event_sem); kfree(priv->cmd.context); + priv->cmd.context = NULL; up(&priv->cmd.poll_sem); up_write(&priv->cmd.switch_sem); @@ -2740,11 +2748,11 @@ void mlx4_cmd_wake_completions(struct mlx4_dev *dev) int i; spin_lock(&priv->cmd.context_lock); - if (priv->cmd.context) { + if (priv->cmd.context != NULL) { for (i = 0; i < priv->cmd.max_cmds; ++i) { context = &priv->cmd.context[i]; context->fw_status = CMD_STAT_INTERNAL_ERR; - context->result = + context->result = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); complete(&context->done); } From c29a65e6eca10cc27aba4e64e1e496129d39782b Mon Sep 17 00:00:00 2001 From: Hans Petter Selasky Date: Mon, 11 Mar 2019 14:34:25 +0000 Subject: [PATCH 11/18] Eliminate useless warning message when reading sysctl node in mlx4core. MFC after: 1 week Sponsored by: Mellanox Technologies --- sys/dev/mlx4/mlx4_core/mlx4_main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sys/dev/mlx4/mlx4_core/mlx4_main.c b/sys/dev/mlx4/mlx4_core/mlx4_main.c index 321c3b1f755..cb5c655b13d 100644 --- a/sys/dev/mlx4/mlx4_core/mlx4_main.c +++ b/sys/dev/mlx4/mlx4_core/mlx4_main.c @@ -1236,9 +1236,6 @@ static ssize_t show_port_ib_mtu(struct device *dev, port_mtu_attr); struct mlx4_dev *mdev = info->dev; - if (mdev->caps.port_type[info->port] == MLX4_PORT_TYPE_ETH) - mlx4_warn(mdev, "port level mtu is only used for IB ports\n"); - sprintf(buf, "%d\n", ibta_mtu_to_int(mdev->caps.port_ib_mtu[info->port])); return strlen(buf); From 1da1f2c2292f2859192f5b6c59134ab7179a873f Mon Sep 17 00:00:00 2001 From: Glen Barber Date: Mon, 11 Mar 2019 15:36:24 +0000 Subject: [PATCH 12/18] Update the re@ member list. Sponsored by: The FreeBSD Foundation --- share/misc/organization.dot | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/misc/organization.dot b/share/misc/organization.dot index ce6c8deede7..a2da8785a65 100644 --- a/share/misc/organization.dot +++ b/share/misc/organization.dot @@ -32,7 +32,7 @@ doceng [label="Documentation Engineering Team\ndoceng@FreeBSD.org\nbcr, gabor, g portscommitters [label="Ports Committers\nports-committers@FreeBSD.org"] portmgr [label="Port Management Team\nportmgr@FreeBSD.org\nadamw, antoine, bapt, bdrewery\nfeld, mat, rene, swills"] portmgrsecretary [label="Port Management Team Secretary\nportmgr-secretary@FreeBSD.org\nrene"] -re [label="Primary Release Engineering Team\nre@FreeBSD.org\ngjb, kib,\nbdrewery, blackend,\nrgrimes, delphij,\nhrs, glebius,\nmarius, rwatson"] +re [label="Primary Release Engineering Team\nre@FreeBSD.org\ngjb, kib,\nbdrewery, blackend,\nrgrimes, delphij,\nhrs, glebius,\nmarius"] secteam [label="Security Team\nsecteam@FreeBSD.org\nbenno, delphij,\ndes, emaste,\ngjb, gordon,\nremko"] portssecteam [label="Ports Security Team\nports-secteam@FreeBSD.org\ndelphij, amdmi3, eadler, feld, jgh, rea, riggs, sbz, simon, swills, zi"] secteamsecretary [label="Security Team Secretary\nsecteam-secretary@FreeBSD.org\nremko"] From 735a3eae280d02517b5567963f8b3f7af4b12466 Mon Sep 17 00:00:00 2001 From: Glen Barber Date: Mon, 11 Mar 2019 15:47:26 +0000 Subject: [PATCH 13/18] Update entries for accounts@, backups@, dnsadm@, mirror-admin@, and remove refadm@. Sponsored by: The FreeBSD Foundation --- share/misc/organization.dot | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/share/misc/organization.dot b/share/misc/organization.dot index a2da8785a65..eaf3d84b6b0 100644 --- a/share/misc/organization.dot +++ b/share/misc/organization.dot @@ -41,15 +41,14 @@ srccommitters [label="Src Committers\nsrc-committers@FreeBSD.org"] # Admin teams go here alphabetically sorted -accounts [label="Accounts Team\naccounts@FreeBSD.org\nmarkm, simon, kensmith,\ndhw"] -backups [label="Backup Administrators\nbackups@FreeBSD.org\nsimon, kensmith,\ndhw"] +accounts [label="Accounts Team\naccounts@FreeBSD.org\nclusteradm"] +backups [label="Backup Administrators\nbackups@FreeBSD.org\nclusteradm"] bugmeister [label="Bugmeister Team\nbugmeister@FreeBSD.org\neadler, gavin, gonzo"] clusteradm [label="Cluster Administrators\nclusteradm@FreeBSD.org\nallanjude, brd,\ndhw, gavin,\ngjb, peter,\nsbruno, simon,\nzi"] -dnsadm [label="DNS Administrators\ndnsadm@FreeBSD.org\nbillf, dg, ps,\nkensmith, peter"] -mirroradmin [label="FTP/WWW Mirror Site Coordinators\nmirror-admin@FreeBSD.org\nkuriyama, kensmith"] +dnsadm [label="DNS Administrators\ndnsadm@FreeBSD.org\nclusteradm"] +mirroradmin [label="FTP/WWW Mirror Site Coordinators\nmirror-admin@FreeBSD.org\nclusteradm,\nkuriyama"] perforceadmin [label="Perforce Repository Administrators\nperforce-admin@FreeBSD.org\nscottl, kensmith, gordon,\nrwatson, peter, dhw"] postmaster [label="Postmaster Team\npostmaster@FreeBSD.org\ndhw, krion, ler, philip, pi, rea, remko, zi"] -refadm [label="Reference Systems Administrators\nrefadm@FreeBSD.org\njake, billf, markm, simon,\nobrien, ps, kensmith,\npeter, dhw"] webmaster [label="Webmaster Team\nwebmaster@FreeBSD.org\ngjb, wblock, blackend,\ngabor, hrs, wosch"] # Misc hats go here alphabetically sorted @@ -69,7 +68,6 @@ _admin -> clusteradm _admin -> dnsadm _admin -> mirroradmin _admin -> perforceadmin -_admin -> refadm _admin -> postmaster _admin -> webmaster From aa8676f25d0644a7e838d72f5d88b5a74958a5b4 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Mon, 11 Mar 2019 17:39:09 +0000 Subject: [PATCH 14/18] Revert minor part of r344934. I tried to save some CPU time on hopeless aggregation attempts, but it seems the condition I added is overly strict, blocking also aggregation of optional I/Os in cases which previously were possible. Revert just to be safe. MFC after: 1 month --- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_queue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_queue.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_queue.c index 556afda1c70..b53ec7ffafc 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_queue.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_queue.c @@ -692,7 +692,7 @@ vdev_queue_aggregate(vdev_queue_t *vq, zio_t *zio) limit = zfs_vdev_aggregation_limit; limit = MAX(MIN(limit, maxblocksize), 0); - if (zio->io_flags & ZIO_FLAG_DONT_AGGREGATE || zio->io_size >= limit) + if (zio->io_flags & ZIO_FLAG_DONT_AGGREGATE || limit == 0) return (NULL); first = last = zio; From e6ec44cf36928e182f1e73267c4f5b7ba71cc9e9 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Mon, 11 Mar 2019 19:15:57 +0000 Subject: [PATCH 15/18] Pull in r355854 from upstream llvm trunk (by Jonas Paulsson): [RegAlloc] Avoid compile time regression with multiple copy hints. As a fix for https://bugs.llvm.org/show_bug.cgi?id=40986 ("excessive compile time building opencollada"), this patch makes sure that no phys reg is hinted more than once from getRegAllocationHints(). This handles the case were many virtual registers are assigned to the same physreg. The previous compile time fix (r343686) in weightCalcHelper() only made sure that physical/virtual registers are passed no more than once to addRegAllocationHint(). Review: Dimitry Andric, Quentin Colombet https://reviews.llvm.org/D59201 This should fix a hang when compiling certain generated .cpp files in the graphics/opencollada port. PR: 236313 MFC after: 1 month X-MFC-With: r344779 --- contrib/llvm/lib/CodeGen/TargetRegisterInfo.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/contrib/llvm/lib/CodeGen/TargetRegisterInfo.cpp b/contrib/llvm/lib/CodeGen/TargetRegisterInfo.cpp index 661dc18f7a8..d3059280a60 100644 --- a/contrib/llvm/lib/CodeGen/TargetRegisterInfo.cpp +++ b/contrib/llvm/lib/CodeGen/TargetRegisterInfo.cpp @@ -14,6 +14,7 @@ #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/CodeGen/MachineFrameInfo.h" @@ -398,6 +399,7 @@ TargetRegisterInfo::getRegAllocationHints(unsigned VirtReg, const std::pair> &Hints_MRI = MRI.getRegAllocationHints(VirtReg); + SmallSet HintedRegs; // First hint may be a target hint. bool Skip = (Hints_MRI.first != 0); for (auto Reg : Hints_MRI.second) { @@ -411,6 +413,10 @@ TargetRegisterInfo::getRegAllocationHints(unsigned VirtReg, if (VRM && isVirtualRegister(Phys)) Phys = VRM->getPhys(Phys); + // Don't add the same reg twice (Hints_MRI may contain multiple virtual + // registers allocated to the same physreg). + if (!HintedRegs.insert(Phys).second) + continue; // Check that Phys is a valid hint in VirtReg's register class. if (!isPhysicalRegister(Phys)) continue; From 76cefcd810370da5ef6554b11db9ec0731bdca40 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratyev Date: Mon, 11 Mar 2019 19:46:15 +0000 Subject: [PATCH 16/18] Fix amd64/i386 LINT build after r344982 Submitted by: jkim Reported by: rpokala MFC with: r344982 --- sys/x86/isa/atrtc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sys/x86/isa/atrtc.c b/sys/x86/isa/atrtc.c index a1d02e8c62a..524d958329c 100644 --- a/sys/x86/isa/atrtc.c +++ b/sys/x86/isa/atrtc.c @@ -83,6 +83,11 @@ static int rtc_reg = -1; static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; static u_char rtc_statusb = RTCSB_24HR; +#ifdef DEV_ACPI +#define _COMPONENT ACPI_TIMER +ACPI_MODULE_NAME("ATRTC") +#endif + /* * RTC support routines */ From f5fdf82d824081ab7fd00a6cd38a7938709b0d06 Mon Sep 17 00:00:00 2001 From: "Simon J. Gerraty" Date: Mon, 11 Mar 2019 20:40:56 +0000 Subject: [PATCH 17/18] Add _PC_ACL_* to vop_stdpathconf This avoid EINVAL from tmpfs etc. Reviewed by: kib Differential Revision: https://reviews.freebsd.org/D19512 --- .../opensolaris/uts/common/fs/zfs/zfs_ctldir.c | 4 ---- sys/fs/nandfs/nandfs_vnops.c | 3 --- sys/fs/nfsclient/nfs_clvnops.c | 6 ------ sys/kern/vfs_default.c | 7 +++++++ sys/ufs/ufs/ufs_vnops.c | 18 ++++-------------- 5 files changed, 11 insertions(+), 27 deletions(-) diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c index b59546f83e7..381dd75f2d0 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c @@ -755,10 +755,6 @@ zfsctl_common_pathconf(ap) *ap->a_retval = (int)SPA_MINBLOCKSIZE; return (0); - case _PC_ACL_EXTENDED: - *ap->a_retval = 0; - return (0); - case _PC_ACL_NFS4: *ap->a_retval = 1; return (0); diff --git a/sys/fs/nandfs/nandfs_vnops.c b/sys/fs/nandfs/nandfs_vnops.c index 1e164f50065..5027d6adbbc 100644 --- a/sys/fs/nandfs/nandfs_vnops.c +++ b/sys/fs/nandfs/nandfs_vnops.c @@ -2258,9 +2258,6 @@ nandfs_pathconf(struct vop_pathconf_args *ap) case _PC_NO_TRUNC: *ap->a_retval = 1; break; - case _PC_ACL_EXTENDED: - *ap->a_retval = 0; - break; case _PC_ALLOC_SIZE_MIN: *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_bsize; break; diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c index 7f9eb26e6ad..8a9067ee4e4 100644 --- a/sys/fs/nfsclient/nfs_clvnops.c +++ b/sys/fs/nfsclient/nfs_clvnops.c @@ -3511,9 +3511,6 @@ nfs_pathconf(struct vop_pathconf_args *ap) case _PC_NO_TRUNC: *ap->a_retval = pc.pc_notrunc; break; - case _PC_ACL_EXTENDED: - *ap->a_retval = 0; - break; case _PC_ACL_NFS4: if (NFS_ISV4(vp) && nfsrv_useacl != 0 && attrflag != 0 && NFSISSET_ATTRBIT(&nfsva.na_suppattr, NFSATTRBIT_ACL)) @@ -3527,9 +3524,6 @@ nfs_pathconf(struct vop_pathconf_args *ap) else *ap->a_retval = 3; break; - case _PC_MAC_PRESENT: - *ap->a_retval = 0; - break; case _PC_PRIO_IO: *ap->a_retval = 0; break; diff --git a/sys/kern/vfs_default.c b/sys/kern/vfs_default.c index 394dcd88fc0..8d349f8604d 100644 --- a/sys/kern/vfs_default.c +++ b/sys/kern/vfs_default.c @@ -482,6 +482,13 @@ vop_stdpathconf(ap) case _PC_PATH_MAX: *ap->a_retval = PATH_MAX; return (0); + case _PC_ACL_EXTENDED: + case _PC_ACL_NFS4: + case _PC_CAP_PRESENT: + case _PC_INF_PRESENT: + case _PC_MAC_PRESENT: + *ap->a_retval = 0; + return (0); default: return (EINVAL); } diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c index 680047737f9..820b093a11c 100644 --- a/sys/ufs/ufs/ufs_vnops.c +++ b/sys/ufs/ufs/ufs_vnops.c @@ -2421,28 +2421,20 @@ ufs_pathconf(ap) case _PC_NO_TRUNC: *ap->a_retval = 1; break; - case _PC_ACL_EXTENDED: #ifdef UFS_ACL + case _PC_ACL_EXTENDED: if (ap->a_vp->v_mount->mnt_flag & MNT_ACLS) *ap->a_retval = 1; else *ap->a_retval = 0; -#else - *ap->a_retval = 0; -#endif break; - case _PC_ACL_NFS4: -#ifdef UFS_ACL if (ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) *ap->a_retval = 1; else *ap->a_retval = 0; -#else - *ap->a_retval = 0; -#endif break; - +#endif case _PC_ACL_PATH_MAX: #ifdef UFS_ACL if (ap->a_vp->v_mount->mnt_flag & (MNT_ACLS | MNT_NFS4ACLS)) @@ -2453,16 +2445,14 @@ ufs_pathconf(ap) *ap->a_retval = 3; #endif break; - case _PC_MAC_PRESENT: #ifdef MAC + case _PC_MAC_PRESENT: if (ap->a_vp->v_mount->mnt_flag & MNT_MULTILABEL) *ap->a_retval = 1; else *ap->a_retval = 0; -#else - *ap->a_retval = 0; -#endif break; +#endif case _PC_MIN_HOLE_SIZE: *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize; break; From 3899afd37063bf8c35fab2d126ab0374044e85ac Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Mon, 11 Mar 2019 20:57:54 +0000 Subject: [PATCH 18/18] Upgrade Chipfancier SLC quirk to all versions The 16GB, 32GB and 128GB versions of this product all have the same problem. For some reason, the RC10 size is correct, while the RC16 size is larger (oddly by the capacity size / 1024 bytes). Using the RC16 size results in illegal LBA range errors when geom tastes the device. So, expand the quirk to cover all versions of this chip. Ideally, we'd get both READ CAPACITY 10 and READ CAPACITY 16 sizes and print a warnnig if they differ and use the smaller of the two numbers, though that may be problematical as well. Furthermore, SBC-4 encourages users transition to RC16 only, which suggests that in the future RC10 may disappear from some drives. It's unclear how to cope with these drives generically. PR: 234503 MFC After: 1 week --- sys/cam/scsi/scsi_da.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c index d7c6b30fca9..c566ffbc4aa 100644 --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -865,11 +865,12 @@ static struct da_quirk_entry da_quirk_table[] = }, { /* - * 16GB SLC CHIPFANCIER - * PR: usb/234503 + * SLC CHIPFANCIER USB drives + * PR: usb/234503 (RC10 right, RC16 wrong) + * 16GB, 32GB and 128GB confirmed to have same issue */ - {T_DIRECT, SIP_MEDIA_REMOVABLE, "16G SLC", "CHIPFANCIER", - "1.00"}, /*quirks*/ DA_Q_NO_RC16 + {T_DIRECT, SIP_MEDIA_REMOVABLE, "*SLC", "CHIPFANCIER", + "*"}, /*quirks*/ DA_Q_NO_RC16 }, /* ATA/SATA devices over SAS/USB/... */ {