MFhead@r345025

This commit is contained in:
Enji Cooper 2019-03-11 21:00:58 +00:00
commit eb1761b004
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/import-googletest-1.8.1/; revision=345026
55 changed files with 4405 additions and 829 deletions

View File

@ -14,6 +14,7 @@
#include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h" #include "llvm/ADT/BitVector.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringExtras.h"
#include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFrameInfo.h"
@ -398,6 +399,7 @@ TargetRegisterInfo::getRegAllocationHints(unsigned VirtReg,
const std::pair<unsigned, SmallVector<unsigned, 4>> &Hints_MRI = const std::pair<unsigned, SmallVector<unsigned, 4>> &Hints_MRI =
MRI.getRegAllocationHints(VirtReg); MRI.getRegAllocationHints(VirtReg);
SmallSet<unsigned, 32> HintedRegs;
// First hint may be a target hint. // First hint may be a target hint.
bool Skip = (Hints_MRI.first != 0); bool Skip = (Hints_MRI.first != 0);
for (auto Reg : Hints_MRI.second) { for (auto Reg : Hints_MRI.second) {
@ -411,6 +413,10 @@ TargetRegisterInfo::getRegAllocationHints(unsigned VirtReg,
if (VRM && isVirtualRegister(Phys)) if (VRM && isVirtualRegister(Phys))
Phys = VRM->getPhys(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. // Check that Phys is a valid hint in VirtReg's register class.
if (!isPhysicalRegister(Phys)) if (!isPhysicalRegister(Phys))
continue; continue;

View File

@ -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.

View File

@ -12,65 +12,101 @@
#if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \ #if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \
!defined(__ARM_DWARF_EH__) !defined(__ARM_DWARF_EH__)
#define _LIBUNWIND_ARM_EHABI 1 #define _LIBUNWIND_ARM_EHABI
#else
#define _LIBUNWIND_ARM_EHABI 0
#endif #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_RISCV 95
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS 65
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC 31
#if defined(_LIBUNWIND_IS_NATIVE_ONLY) #if defined(_LIBUNWIND_IS_NATIVE_ONLY)
# if defined(__i386__) # if defined(__i386__)
# define _LIBUNWIND_TARGET_I386 1 # define _LIBUNWIND_TARGET_I386
# define _LIBUNWIND_CONTEXT_SIZE 8 # define _LIBUNWIND_CONTEXT_SIZE 8
# define _LIBUNWIND_CURSOR_SIZE 19 # define _LIBUNWIND_CURSOR_SIZE 15
# define _LIBUNWIND_MAX_REGISTER 9 # define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86
# elif defined(__x86_64__) # elif defined(__x86_64__)
# define _LIBUNWIND_TARGET_X86_64 1 # define _LIBUNWIND_TARGET_X86_64 1
# define _LIBUNWIND_CONTEXT_SIZE 21 # if defined(_WIN64)
# define _LIBUNWIND_CURSOR_SIZE 33 # define _LIBUNWIND_CONTEXT_SIZE 54
# define _LIBUNWIND_MAX_REGISTER 17 # 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__) # elif defined(__ppc__)
# define _LIBUNWIND_TARGET_PPC 1 # define _LIBUNWIND_TARGET_PPC 1
# define _LIBUNWIND_CONTEXT_SIZE 117 # define _LIBUNWIND_CONTEXT_SIZE 117
# define _LIBUNWIND_CURSOR_SIZE 128 # define _LIBUNWIND_CURSOR_SIZE 124
# define _LIBUNWIND_MAX_REGISTER 113 # define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC
# elif defined(__aarch64__) # elif defined(__aarch64__)
# define _LIBUNWIND_TARGET_AARCH64 1 # define _LIBUNWIND_TARGET_AARCH64 1
# define _LIBUNWIND_CONTEXT_SIZE 66 # define _LIBUNWIND_CONTEXT_SIZE 66
# define _LIBUNWIND_CURSOR_SIZE 78 # if defined(__SEH__)
# define _LIBUNWIND_MAX_REGISTER 96 # 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__) # elif defined(__arm__)
# define _LIBUNWIND_TARGET_ARM 1 # define _LIBUNWIND_TARGET_ARM 1
# define _LIBUNWIND_CONTEXT_SIZE 60 # if defined(__SEH__)
# define _LIBUNWIND_CURSOR_SIZE 67 # define _LIBUNWIND_CONTEXT_SIZE 42
# define _LIBUNWIND_MAX_REGISTER 96 # 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__) # elif defined(__or1k__)
# define _LIBUNWIND_TARGET_OR1K 1 # define _LIBUNWIND_TARGET_OR1K 1
# define _LIBUNWIND_CONTEXT_SIZE 16 # define _LIBUNWIND_CONTEXT_SIZE 16
# define _LIBUNWIND_CURSOR_SIZE 28 # define _LIBUNWIND_CURSOR_SIZE 24
# define _LIBUNWIND_MAX_REGISTER 32 # define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K
# elif defined(__riscv) # elif defined(__riscv)
# define _LIBUNWIND_TARGET_RISCV 1 # define _LIBUNWIND_TARGET_RISCV 1
# define _LIBUNWIND_CONTEXT_SIZE 64 # define _LIBUNWIND_CONTEXT_SIZE 64
# define _LIBUNWIND_CURSOR_SIZE 76 # define _LIBUNWIND_CURSOR_SIZE 76
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV
# define _LIBUNWIND_MAX_REGISTER 96 # define _LIBUNWIND_MAX_REGISTER 96
# elif defined(__mips__) # elif defined(__mips__)
# if defined(_ABIO32) && _MIPS_SIM == _ABIO32 # if defined(_ABIO32) && _MIPS_SIM == _ABIO32
# define _LIBUNWIND_TARGET_MIPS_O32 1 # define _LIBUNWIND_TARGET_MIPS_O32 1
# if defined(__mips_hard_float) # if defined(__mips_hard_float)
# define _LIBUNWIND_CONTEXT_SIZE 50 # define _LIBUNWIND_CONTEXT_SIZE 50
# define _LIBUNWIND_CURSOR_SIZE 61 # define _LIBUNWIND_CURSOR_SIZE 57
# else # else
# define _LIBUNWIND_CONTEXT_SIZE 18 # define _LIBUNWIND_CONTEXT_SIZE 18
# define _LIBUNWIND_CURSOR_SIZE 29 # define _LIBUNWIND_CURSOR_SIZE 24
# endif # endif
# elif defined(_ABIN32) && _MIPS_SIM == _ABIN32 # elif defined(_ABIN32) && _MIPS_SIM == _ABIN32
# define _LIBUNWIND_TARGET_MIPS_NEWABI 1 # define _LIBUNWIND_TARGET_MIPS_NEWABI 1
# if defined(__mips_hard_float) # if defined(__mips_hard_float)
# define _LIBUNWIND_CONTEXT_SIZE 67 # define _LIBUNWIND_CONTEXT_SIZE 67
# define _LIBUNWIND_CURSOR_SIZE 78 # define _LIBUNWIND_CURSOR_SIZE 74
# else # else
# define _LIBUNWIND_CONTEXT_SIZE 35 # define _LIBUNWIND_CONTEXT_SIZE 35
# define _LIBUNWIND_CURSOR_SIZE 46 # define _LIBUNWIND_CURSOR_SIZE 42
# endif # endif
# elif defined(_ABI64) && _MIPS_SIM == _ABI64 # elif defined(_ABI64) && _MIPS_SIM == _ABI64
# define _LIBUNWIND_TARGET_MIPS_NEWABI 1 # define _LIBUNWIND_TARGET_MIPS_NEWABI 1
@ -84,22 +120,29 @@
# else # else
# error "Unsupported MIPS ABI and/or environment" # error "Unsupported MIPS ABI and/or environment"
# endif # endif
# define _LIBUNWIND_MAX_REGISTER 66 # 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 # else
# error "Unsupported architecture." # error "Unsupported architecture."
# endif # endif
#else // !_LIBUNWIND_IS_NATIVE_ONLY #else // !_LIBUNWIND_IS_NATIVE_ONLY
# define _LIBUNWIND_TARGET_I386 1 # define _LIBUNWIND_TARGET_I386
# define _LIBUNWIND_TARGET_X86_64 1 # define _LIBUNWIND_TARGET_X86_64 1
# define _LIBUNWIND_TARGET_PPC 1 # define _LIBUNWIND_TARGET_PPC 1
# define _LIBUNWIND_TARGET_PPC64 1
# define _LIBUNWIND_TARGET_AARCH64 1 # define _LIBUNWIND_TARGET_AARCH64 1
# define _LIBUNWIND_TARGET_ARM 1 # define _LIBUNWIND_TARGET_ARM 1
# define _LIBUNWIND_TARGET_OR1K 1 # define _LIBUNWIND_TARGET_OR1K 1
# define _LIBUNWIND_TARGET_MIPS_O32 1 # define _LIBUNWIND_TARGET_MIPS_O32 1
# define _LIBUNWIND_TARGET_MIPS_NEWABI 1 # define _LIBUNWIND_TARGET_MIPS_NEWABI 1
# define _LIBUNWIND_CONTEXT_SIZE 128 # define _LIBUNWIND_TARGET_SPARC 1
# define _LIBUNWIND_CURSOR_SIZE 140 # define _LIBUNWIND_CONTEXT_SIZE 167
# define _LIBUNWIND_MAX_REGISTER 120 # define _LIBUNWIND_CURSOR_SIZE 179
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287
#endif // _LIBUNWIND_IS_NATIVE_ONLY #endif // _LIBUNWIND_IS_NATIVE_ONLY
#endif // ____LIBUNWIND_CONFIG_H__ #endif // ____LIBUNWIND_CONFIG_H__

View File

@ -20,12 +20,26 @@
#include <stddef.h> #include <stddef.h>
#ifdef __APPLE__ #ifdef __APPLE__
#include <Availability.h> #if __clang__
#ifdef __arm__ #if __has_include(<Availability.h>)
#define LIBUNWIND_AVAIL __attribute__((unavailable)) #include <Availability.h>
#else
#define LIBUNWIND_AVAIL __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_5_0)
#endif #endif
#elif __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050
#include <Availability.h>
#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 <AvailabilityMacros.h>
#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 #else
#define LIBUNWIND_AVAIL #define LIBUNWIND_AVAIL
#endif #endif
@ -43,6 +57,9 @@ enum {
UNW_EINVAL = -6547, /* unsupported operation or bad value */ UNW_EINVAL = -6547, /* unsupported operation or bad value */
UNW_EBADVERSION = -6548, /* unwind info has unsupported version */ UNW_EBADVERSION = -6548, /* unwind info has unsupported version */
UNW_ENOINFO = -6549 /* no unwind info found */ 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 { 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 struct unw_addr_space *unw_addr_space_t;
typedef int unw_regnum_t; typedef int unw_regnum_t;
#if _LIBUNWIND_ARM_EHABI typedef uintptr_t unw_word_t;
typedef uint32_t unw_word_t; #if defined(__arm__)
typedef uint64_t unw_fpreg_t; typedef uint64_t unw_fpreg_t;
#else #else
typedef uint64_t unw_word_t;
typedef double unw_fpreg_t; typedef double unw_fpreg_t;
#endif #endif
@ -75,8 +91,8 @@ struct unw_proc_info_t {
unw_word_t gp; /* not used */ unw_word_t gp; /* not used */
unw_word_t flags; /* not used */ unw_word_t flags; /* not used */
uint32_t format; /* compact unwind encoding, or zero if none */ uint32_t format; /* compact unwind encoding, or zero if none */
uint32_t unwind_info_size; /* size of dwarf unwind info, 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 */ unw_word_t unwind_info; /* address of DWARF unwind info, or zero */
unw_word_t extra; /* mach_header of mach-o image containing func */ unw_word_t extra; /* mach_header of mach-o image containing func */
}; };
typedef struct unw_proc_info_t unw_proc_info_t; typedef struct unw_proc_info_t unw_proc_info_t;
@ -151,8 +167,8 @@ enum {
UNW_X86_ECX = 1, UNW_X86_ECX = 1,
UNW_X86_EDX = 2, UNW_X86_EDX = 2,
UNW_X86_EBX = 3, UNW_X86_EBX = 3,
UNW_X86_ESP = 4, UNW_X86_EBP = 4,
UNW_X86_EBP = 5, UNW_X86_ESP = 5,
UNW_X86_ESI = 6, UNW_X86_ESI = 6,
UNW_X86_EDI = 7 UNW_X86_EDI = 7
}; };
@ -174,7 +190,24 @@ enum {
UNW_X86_64_R12 = 12, UNW_X86_64_R12 = 12,
UNW_X86_64_R13 = 13, UNW_X86_64_R13 = 13,
UNW_X86_64_R14 = 14, 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 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 // 64-bit ARM64 registers
enum { enum {
UNW_ARM64_X0 = 0, UNW_ARM64_X0 = 0,
@ -333,6 +550,8 @@ enum {
UNW_ARM64_X31 = 31, UNW_ARM64_X31 = 31,
UNW_ARM64_SP = 31, UNW_ARM64_SP = 31,
// reserved block // reserved block
UNW_ARM64_RA_SIGN_STATE = 34,
// reserved block
UNW_ARM64_D0 = 64, UNW_ARM64_D0 = 64,
UNW_ARM64_D1 = 65, UNW_ARM64_D1 = 65,
UNW_ARM64_D2 = 66, UNW_ARM64_D2 = 66,
@ -531,6 +750,7 @@ enum {
UNW_OR1K_R29 = 29, UNW_OR1K_R29 = 29,
UNW_OR1K_R30 = 30, UNW_OR1K_R30 = 30,
UNW_OR1K_R31 = 31, UNW_OR1K_R31 = 31,
UNW_OR1K_EPCR = 32,
}; };
// 64-bit RISC-V registers // 64-bit RISC-V registers
@ -674,4 +894,40 @@ enum {
UNW_MIPS_LO = 65, 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 #endif

View File

@ -6,7 +6,7 @@
// Source Licenses. See LICENSE.TXT for details. // 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 <stdint.h> #include <stdint.h>
// //
// 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 // of object files. Or compilers can emit compact unwind information in
// the __LD,__compact_unwind section. // the __LD,__compact_unwind section.
// //
@ -26,10 +26,10 @@
// runtime to access unwind info for any given function. If the compiler // runtime to access unwind info for any given function. If the compiler
// emitted compact unwind info for the function, that compact unwind info will // emitted compact unwind info for the function, that compact unwind info will
// be encoded in the __TEXT,__unwind_info section. If the compiler emitted // 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. // 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. // compact unwind info. But that is fragile and no longer done.
@ -58,7 +58,7 @@ enum {
// 1-bit: has lsda // 1-bit: has lsda
// 2-bit: personality index // 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: // ebp based:
// 15-bits (5*3-bits per reg) register permutation // 15-bits (5*3-bits per reg) register permutation
// 8-bits for stack offset // 8-bits for stack offset
@ -128,9 +128,9 @@ enum {
// UNWIND_X86_FRAMELESS_STACK_SIZE. // UNWIND_X86_FRAMELESS_STACK_SIZE.
// UNWIND_X86_MODE_DWARF: // UNWIND_X86_MODE_DWARF:
// No compact unwind encoding is available. Instead the low 24-bits of the // 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 // 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. // function.
// //
// The permutation encoding is a Lehmer code sequence encoded into a // The permutation encoding is a Lehmer code sequence encoded into a
@ -193,7 +193,7 @@ enum {
// 1-bit: has lsda // 1-bit: has lsda
// 2-bit: personality index // 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: // rbp based:
// 15-bits (5*3-bits per reg) register permutation // 15-bits (5*3-bits per reg) register permutation
// 8-bits for stack offset // 8-bits for stack offset
@ -262,9 +262,9 @@ enum {
// UNWIND_X86_64_FRAMELESS_STACK_SIZE. // UNWIND_X86_64_FRAMELESS_STACK_SIZE.
// UNWIND_X86_64_MODE_DWARF: // UNWIND_X86_64_MODE_DWARF:
// No compact unwind encoding is available. Instead the low 24-bits of the // 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 // 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. // function.
// //
@ -275,14 +275,14 @@ enum {
// 1-bit: has lsda // 1-bit: has lsda
// 2-bit: personality index // 2-bit: personality index
// //
// 4-bits: 4=frame-based, 3=dwarf, 2=frameless // 4-bits: 4=frame-based, 3=DWARF, 2=frameless
// frameless: // frameless:
// 12-bits of stack size // 12-bits of stack size
// frame-based: // frame-based:
// 4-bits D reg pairs saved // 4-bits D reg pairs saved
// 5-bits X reg pairs saved // 5-bits X reg pairs saved
// dwarf: // DWARF:
// 24-bits offset of dwarf FDE in __eh_frame section // 24-bits offset of DWARF FDE in __eh_frame section
// //
enum { enum {
UNWIND_ARM64_MODE_MASK = 0x0F000000, UNWIND_ARM64_MODE_MASK = 0x0F000000,
@ -320,9 +320,9 @@ enum {
// UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK. // UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK.
// UNWIND_ARM64_MODE_DWARF: // UNWIND_ARM64_MODE_DWARF:
// No compact unwind encoding is available. Instead the low 24-bits of the // 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 // 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. // function.
// //
@ -385,7 +385,7 @@ enum {
// saved at that range of the function. // saved at that range of the function.
// //
// If a particular function is so wacky that there is no compact unwind way // 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. // The runtime will use which ever is available.
// //
// Runtime support for compact unwind encodings are only available on 10.6 // Runtime support for compact unwind encodings are only available on 10.6

View File

@ -19,6 +19,11 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) && defined(_WIN32)
#include <windows.h>
#include <ntverp.h>
#endif
#if defined(__APPLE__) #if defined(__APPLE__)
#define LIBUNWIND_UNAVAIL __attribute__ (( unavailable )) #define LIBUNWIND_UNAVAIL __attribute__ (( unavailable ))
#else #else
@ -36,7 +41,7 @@ typedef enum {
_URC_HANDLER_FOUND = 6, _URC_HANDLER_FOUND = 6,
_URC_INSTALL_CONTEXT = 7, _URC_INSTALL_CONTEXT = 7,
_URC_CONTINUE_UNWIND = 8, _URC_CONTINUE_UNWIND = 8,
#if _LIBUNWIND_ARM_EHABI #if defined(_LIBUNWIND_ARM_EHABI)
_URC_FAILURE = 9 _URC_FAILURE = 9
#endif #endif
} _Unwind_Reason_Code; } _Unwind_Reason_Code;
@ -51,12 +56,13 @@ typedef enum {
typedef struct _Unwind_Context _Unwind_Context; // opaque typedef struct _Unwind_Context _Unwind_Context; // opaque
#if _LIBUNWIND_ARM_EHABI #if defined(_LIBUNWIND_ARM_EHABI)
typedef uint32_t _Unwind_State; typedef uint32_t _Unwind_State;
static const _Unwind_State _US_VIRTUAL_UNWIND_FRAME = 0; 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_STARTING = 1;
static const _Unwind_State _US_UNWIND_FRAME_RESUME = 2; static const _Unwind_State _US_UNWIND_FRAME_RESUME = 2;
static const _Unwind_State _US_ACTION_MASK = 3;
/* Undocumented flag for force unwinding. */ /* Undocumented flag for force unwinding. */
static const _Unwind_State _US_FORCE_UNWIND = 8; static const _Unwind_State _US_FORCE_UNWIND = 8;
@ -99,7 +105,7 @@ struct _Unwind_Control_Block {
} pr_cache; } pr_cache;
long long int :0; /* Enforce the 8-byte alignment */ long long int :0; /* Enforce the 8-byte alignment */
}; } __attribute__((__aligned__(8)));
typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
(_Unwind_State state, (_Unwind_State state,
@ -119,15 +125,22 @@ struct _Unwind_Exception {
uint64_t exception_class; uint64_t exception_class;
void (*exception_cleanup)(_Unwind_Reason_Code reason, void (*exception_cleanup)(_Unwind_Reason_Code reason,
_Unwind_Exception *exc); _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_1; // non-zero means forced unwind
uintptr_t private_2; // holds sp that phase1 found for phase2 to use uintptr_t private_2; // holds sp that phase1 found for phase2 to use
#ifndef __LP64__ #endif
// The gcc implementation of _Unwind_Exception used attribute mode on the #if __SIZEOF_POINTER__ == 4
// above fields which had the side effect of causing this whole struct to // The implementation of _Unwind_Exception uses an attribute mode on the
// round up to 32 bytes in size. To be more explicit, we add pad fields // above fields which has the side effect of causing this whole struct to
// added for binary compatibility. // 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]; uint32_t reserved[3];
#endif #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__)); } __attribute__((__aligned__));
typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
@ -164,7 +177,7 @@ extern void _Unwind_Resume(_Unwind_Exception *exception_object);
#endif #endif
extern void _Unwind_DeleteException(_Unwind_Exception *exception_object); extern void _Unwind_DeleteException(_Unwind_Exception *exception_object);
#if _LIBUNWIND_ARM_EHABI #if defined(_LIBUNWIND_ARM_EHABI)
typedef enum { typedef enum {
_UVRSC_CORE = 0, /* integer register */ _UVRSC_CORE = 0, /* integer register */
_UVRSC_VFP = 1, /* vfp */ _UVRSC_VFP = 1, /* vfp */
@ -204,7 +217,7 @@ _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
_Unwind_VRS_DataRepresentation representation); _Unwind_VRS_DataRepresentation representation);
#endif #endif
#if !_LIBUNWIND_ARM_EHABI #if !defined(_LIBUNWIND_ARM_EHABI)
extern uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index); extern uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index);
extern void _Unwind_SetGR(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 uintptr_t _Unwind_GetIP(struct _Unwind_Context *context);
extern void _Unwind_SetIP(struct _Unwind_Context *, uintptr_t new_value); 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) #if defined(_LIBUNWIND_UNWIND_LEVEL1_EXTERNAL_LINKAGE)
#define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 extern #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); uintptr_t thumb_bit = _Unwind_GetGR(context, 15) & ((uintptr_t)0x1);
_Unwind_SetGR(context, 15, value | thumb_bit); _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 _Unwind_GetRegionStart(struct _Unwind_Context *context);
extern uintptr_t 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 // _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 // 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 // function will only work if the target function has an FDE but no compact
// unwind info. // unwind info.
struct dwarf_eh_bases { 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 // 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 // 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 // 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. // _Unwind_Find_FDE() and look at the dwarf_eh_bases.func result.
extern void *_Unwind_FindEnclosingFunction(void *pc); 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) extern void *__deregister_frame_info_bases(const void *fde)
LIBUNWIND_UNAVAIL; 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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -18,7 +18,15 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#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 <dlfcn.h> #include <dlfcn.h>
#endif #endif
@ -32,73 +40,137 @@ namespace libunwind {
#include "libunwind.h" #include "libunwind.h"
#include "config.h" #include "config.h"
#include "dwarf2.h" #include "dwarf2.h"
#include "EHHeaderParser.hpp"
#include "Registers.hpp" #include "Registers.hpp"
#if _LIBUNWIND_ARM_EHABI #ifdef __APPLE__
#if defined(__FreeBSD__) || defined(__NetBSD__)
#include <sys/link_elf.h> struct dyld_unwind_sections
typedef void *_Unwind_Ptr; {
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; if (!info->dwarf_section) {
extern "C" _Unwind_Ptr __gnu_Unwind_Find_exidx(_Unwind_Ptr addr, int *len); info->dwarf_section_length = 0;
}
// Emulate the BSD dl_unwind_find_exidx API when on a GNU libdl system. if (!info->compact_unwind_section) {
#define dl_unwind_find_exidx __gnu_Unwind_Find_exidx 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 <link.h>
#else // !defined(_LIBUNWIND_IS_BAREMETAL)
// When statically linked on bare-metal, the symbols for the EH table are looked // When statically linked on bare-metal, the symbols for the EH table are looked
// up without going through the dynamic loader. // 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__) || \ // The following linker script may be used to produce the necessary sections and symbols.
defined(__NetBSD__) // Unless the --eh-frame-hdr linker option is provided, the section is not generated
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND && _LIBUNWIND_SUPPORT_DWARF_INDEX // 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 <link.h> on some
// systems (e.g., FreeBSD). On these systems the data structures are
// just called Elf_XXX. Define ElfW() locally.
#ifndef _WIN32
#include <link.h> #include <link.h>
// Macro for machine-independent access to the ELF program headers. This #else
// macro is not available on some systems (e.g., FreeBSD). On these #include <windows.h>
// systems the data structures are just called Elf_XXX. Define ElfW() #include <psapi.h>
// locally. #endif
#if !defined(ElfW) #if !defined(ElfW)
#define ElfW(type) Elf_##type #define ElfW(type) Elf_##type
#endif #endif
#include "EHHeaderParser.hpp"
#endif
#endif #endif
namespace libunwind { namespace libunwind {
/// Used by findUnwindSections() to return info about needed sections. /// Used by findUnwindSections() to return info about needed sections.
struct UnwindInfoSections { struct UnwindInfoSections {
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND || _LIBUNWIND_SUPPORT_DWARF_INDEX || \ #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) || \
_LIBUNWIND_SUPPORT_COMPACT_UNWIND defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
// No dso_base for ARM EHABI. // No dso_base for SEH or ARM EHABI.
uintptr_t dso_base; uintptr_t dso_base;
#endif #endif
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
uintptr_t dwarf_section; uintptr_t dwarf_section;
uintptr_t dwarf_section_length; uintptr_t dwarf_section_length;
#endif #endif
#if _LIBUNWIND_SUPPORT_DWARF_INDEX #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
uintptr_t dwarf_index_section; uintptr_t dwarf_index_section;
uintptr_t dwarf_index_section_length; uintptr_t dwarf_index_section_length;
#endif #endif
#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
uintptr_t compact_unwind_section; uintptr_t compact_unwind_section;
uintptr_t compact_unwind_section_length; uintptr_t compact_unwind_section_length;
#endif #endif
#if _LIBUNWIND_ARM_EHABI #if defined(_LIBUNWIND_ARM_EHABI)
uintptr_t arm_section; uintptr_t arm_section;
uintptr_t arm_section_length; uintptr_t arm_section_length;
#endif #endif
@ -108,15 +180,10 @@ struct UnwindInfoSections {
/// LocalAddressSpace is used as a template parameter to UnwindCursor when /// LocalAddressSpace is used as a template parameter to UnwindCursor when
/// unwinding a thread in the same process. The wrappers compile away, /// unwinding a thread in the same process. The wrappers compile away,
/// making local unwinds fast. /// making local unwinds fast.
class __attribute__((visibility("hidden"))) LocalAddressSpace { class _LIBUNWIND_HIDDEN LocalAddressSpace {
public: public:
#ifdef __LP64__ typedef uintptr_t pint_t;
typedef uint64_t pint_t; typedef intptr_t sint_t;
typedef int64_t sint_t;
#else
typedef uint32_t pint_t;
typedef int32_t sint_t;
#endif
uint8_t get8(pint_t addr) { uint8_t get8(pint_t addr) {
uint8_t val; uint8_t val;
memcpy(&val, (void *)addr, sizeof(val)); memcpy(&val, (void *)addr, sizeof(val));
@ -163,7 +230,7 @@ class __attribute__((visibility("hidden"))) LocalAddressSpace {
}; };
inline uintptr_t LocalAddressSpace::getP(pint_t addr) { inline uintptr_t LocalAddressSpace::getP(pint_t addr) {
#ifdef __LP64__ #if __SIZEOF_POINTER__ == 8
return get64(addr); return get64(addr);
#else #else
return get32(addr); return get32(addr);
@ -171,7 +238,7 @@ inline uintptr_t LocalAddressSpace::getP(pint_t addr) {
} }
inline uint64_t LocalAddressSpace::getRegister(pint_t addr) { inline uint64_t LocalAddressSpace::getRegister(pint_t addr) {
#if defined(__LP64__) || defined(__mips64) #if __SIZEOF_POINTER__ == 8 || defined(__mips64)
return get64(addr); return get64(addr);
#else #else
return get32(addr); return get32(addr);
@ -219,7 +286,7 @@ inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
} while (byte & 0x80); } while (byte & 0x80);
// sign extend negative numbers // sign extend negative numbers
if ((byte & 0x40) != 0) if ((byte & 0x40) != 0)
result |= (-1LL) << bit; result |= (-1ULL) << bit;
addr = (pint_t) p; addr = (pint_t) p;
return result; return result;
} }
@ -316,55 +383,13 @@ LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
return result; 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, inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
UnwindInfoSections &info) { UnwindInfoSections &info) {
#ifdef __APPLE__ #ifdef __APPLE__
dyld_unwind_sections dyldInfo; dyld_unwind_sections dyldInfo;
if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) { if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
info.dso_base = (uintptr_t)dyldInfo.mh; 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 = (uintptr_t)dyldInfo.dwarf_section;
info.dwarf_section_length = dyldInfo.dwarf_section_length; info.dwarf_section_length = dyldInfo.dwarf_section_length;
#endif #endif
@ -372,23 +397,76 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length; info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
return true; return true;
} }
#elif _LIBUNWIND_ARM_EHABI #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
#ifdef _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 // Bare metal is statically linked, so no need to ask the dynamic loader
info.arm_section = (uintptr_t)(&__exidx_start); info.arm_section = (uintptr_t)(&__exidx_start);
info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start); info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start);
#else _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
int length = 0; (void *)info.arm_section, (void *)info.arm_section_length);
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",
info.arm_section, info.arm_section_length);
if (info.arm_section && info.arm_section_length) if (info.arm_section && info.arm_section_length)
return true; return true;
#elif _LIBUNWIND_SUPPORT_DWARF_UNWIND #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
#if _LIBUNWIND_SUPPORT_DWARF_INDEX 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 { struct dl_iterate_cb_data {
LocalAddressSpace *addressSpace; LocalAddressSpace *addressSpace;
UnwindInfoSections *sects; UnwindInfoSections *sects;
@ -399,7 +477,6 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
int found = dl_iterate_phdr( int found = dl_iterate_phdr(
[](struct dl_phdr_info *pinfo, size_t, void *data) -> int { [](struct dl_phdr_info *pinfo, size_t, void *data) -> int {
auto cbdata = static_cast<dl_iterate_cb_data *>(data); auto cbdata = static_cast<dl_iterate_cb_data *>(data);
size_t object_length;
bool found_obj = false; bool found_obj = false;
bool found_hdr = false; bool found_hdr = false;
@ -416,11 +493,32 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
#if !defined(Elf_Phdr) #if !defined(Elf_Phdr)
typedef ElfW(Phdr) Elf_Phdr; typedef ElfW(Phdr) Elf_Phdr;
#endif #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<Elf_Addr>(pinfo->dlpi_phdr) -
reinterpret_cast<const Elf_Phdr *>(pinfo->dlpi_phdr)
->p_offset
: 0;
#endif
for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) { for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i]; const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
if (phdr->p_type == PT_LOAD) { if (phdr->p_type == PT_LOAD) {
uintptr_t begin = pinfo->dlpi_addr + phdr->p_vaddr; 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; uintptr_t end = begin + phdr->p_memsz;
if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) { if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
cbdata->sects->dso_base = begin; cbdata->sects->dso_base = begin;
@ -430,13 +528,17 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
} else if (phdr->p_type == PT_GNU_EH_FRAME) { } else if (phdr->p_type == PT_GNU_EH_FRAME) {
EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo; EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
uintptr_t eh_frame_hdr_start = pinfo->dlpi_addr + phdr->p_vaddr; 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 = eh_frame_hdr_start;
cbdata->sects->dwarf_index_section_length = phdr->p_memsz; cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
EHHeaderParser<LocalAddressSpace>::decodeEHHdr( found_hdr = EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
*cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz, *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
hdrInfo); hdrInfo);
cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr; if (found_hdr)
found_hdr = true; cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
} }
} }
@ -446,12 +548,26 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
} else { } else {
return false; 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); &cb_data);
return static_cast<bool>(found); return static_cast<bool>(found);
#else
#error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform."
#endif
#endif #endif
return false; return false;
@ -472,7 +588,7 @@ inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf, inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
size_t bufLen, size_t bufLen,
unw_word_t *offset) { unw_word_t *offset) {
#ifndef _LIBUNWIND_IS_BAREMETAL #if _LIBUNWIND_USE_DLADDR
Dl_info dyldInfo; Dl_info dyldInfo;
if (dladdr((void *)addr, &dyldInfo)) { if (dladdr((void *)addr, &dyldInfo)) {
if (dyldInfo.dli_sname != NULL) { if (dyldInfo.dli_sname != NULL) {
@ -489,14 +605,14 @@ inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
#ifdef UNW_REMOTE #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 /// unwinding a thread in the another process. The other process can be a
/// different endianness and a different pointer size which is handled by /// different endianness and a different pointer size which is handled by
/// the P template parameter. /// the P template parameter.
template <typename P> template <typename P>
class OtherAddressSpace { class RemoteAddressSpace {
public: public:
OtherAddressSpace(task_t task) : fTask(task) {} RemoteAddressSpace(task_t task) : fTask(task) {}
typedef typename P::uint_t pint_t; typedef typename P::uint_t pint_t;
@ -520,24 +636,24 @@ class OtherAddressSpace {
task_t fTask; task_t fTask;
}; };
template <typename P> uint8_t OtherAddressSpace<P>::get8(pint_t addr) { template <typename P> uint8_t RemoteAddressSpace<P>::get8(pint_t addr) {
return *((uint8_t *)localCopy(addr)); return *((uint8_t *)localCopy(addr));
} }
template <typename P> uint16_t OtherAddressSpace<P>::get16(pint_t addr) { template <typename P> uint16_t RemoteAddressSpace<P>::get16(pint_t addr) {
return P::E::get16(*(uint16_t *)localCopy(addr)); return P::E::get16(*(uint16_t *)localCopy(addr));
} }
template <typename P> uint32_t OtherAddressSpace<P>::get32(pint_t addr) { template <typename P> uint32_t RemoteAddressSpace<P>::get32(pint_t addr) {
return P::E::get32(*(uint32_t *)localCopy(addr)); return P::E::get32(*(uint32_t *)localCopy(addr));
} }
template <typename P> uint64_t OtherAddressSpace<P>::get64(pint_t addr) { template <typename P> uint64_t RemoteAddressSpace<P>::get64(pint_t addr) {
return P::E::get64(*(uint64_t *)localCopy(addr)); return P::E::get64(*(uint64_t *)localCopy(addr));
} }
template <typename P> template <typename P>
typename P::uint_t OtherAddressSpace<P>::getP(pint_t addr) { typename P::uint_t RemoteAddressSpace<P>::getP(pint_t addr) {
return P::getP(*(uint64_t *)localCopy(addr)); return P::getP(*(uint64_t *)localCopy(addr));
} }
@ -557,7 +673,7 @@ uint64_t OtherAddressSpace<P>::getULEB128(pint_t &addr, pint_t end) {
} }
template <typename P> template <typename P>
int64_t OtherAddressSpace<P>::getSLEB128(pint_t &addr, pint_t end) { int64_t RemoteAddressSpace<P>::getSLEB128(pint_t &addr, pint_t end) {
uintptr_t size = (end - addr); uintptr_t size = (end - addr);
LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr); LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr);
LocalAddressSpace::pint_t sladdr = laddr; LocalAddressSpace::pint_t sladdr = laddr;
@ -566,13 +682,14 @@ int64_t OtherAddressSpace<P>::getSLEB128(pint_t &addr, pint_t end) {
return result; return result;
} }
template <typename P> void *OtherAddressSpace<P>::localCopy(pint_t addr) { template <typename P> void *RemoteAddressSpace<P>::localCopy(pint_t addr) {
// FIX ME // FIX ME
} }
template <typename P> template <typename P>
bool OtherAddressSpace<P>::findFunctionName(pint_t addr, char *buf, bool RemoteAddressSpace<P>::findFunctionName(pint_t addr, char *buf,
size_t bufLen, unw_word_t *offset) { size_t bufLen,
unw_word_t *offset) {
// FIX ME // FIX ME
} }
@ -588,7 +705,7 @@ struct unw_addr_space {
/// a 32-bit intel process. /// a 32-bit intel process.
struct unw_addr_space_i386 : public unw_addr_space { struct unw_addr_space_i386 : public unw_addr_space {
unw_addr_space_i386(task_t task) : oas(task) {} unw_addr_space_i386(task_t task) : oas(task) {}
OtherAddressSpace<Pointer32<LittleEndian> > oas; RemoteAddressSpace<Pointer32<LittleEndian>> oas;
}; };
/// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t /// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t
@ -596,7 +713,7 @@ struct unw_addr_space_i386 : public unw_addr_space {
/// a 64-bit intel process. /// a 64-bit intel process.
struct unw_addr_space_x86_64 : public unw_addr_space { struct unw_addr_space_x86_64 : public unw_addr_space {
unw_addr_space_x86_64(task_t task) : oas(task) {} unw_addr_space_x86_64(task_t task) : oas(task) {}
OtherAddressSpace<Pointer64<LittleEndian> > oas; RemoteAddressSpace<Pointer64<LittleEndian>> oas;
}; };
/// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points /// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points
@ -604,7 +721,14 @@ struct unw_addr_space_x86_64 : public unw_addr_space {
/// a 32-bit PowerPC process. /// a 32-bit PowerPC process.
struct unw_addr_space_ppc : public unw_addr_space { struct unw_addr_space_ppc : public unw_addr_space {
unw_addr_space_ppc(task_t task) : oas(task) {} unw_addr_space_ppc(task_t task) : oas(task) {}
OtherAddressSpace<Pointer32<BigEndian> > oas; RemoteAddressSpace<Pointer32<BigEndian>> 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<Pointer64<LittleEndian>> oas;
}; };
#endif // UNW_REMOTE #endif // UNW_REMOTE

View File

@ -19,7 +19,6 @@
#include <libunwind.h> #include <libunwind.h>
#include <mach-o/compact_unwind_encoding.h> #include <mach-o/compact_unwind_encoding.h>
#include "AddressSpace.hpp"
#include "Registers.hpp" #include "Registers.hpp"
#define EXTRACT_BITS(value, mask) \ #define EXTRACT_BITS(value, mask) \

View File

@ -6,7 +6,7 @@
// Source Licenses. See LICENSE.TXT for details. // 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 <stdlib.h> #include <stdlib.h>
#include "dwarf2.h" #include "dwarf2.h"
#include "AddressSpace.hpp"
#include "Registers.hpp" #include "Registers.hpp"
#include "DwarfParser.hpp" #include "DwarfParser.hpp"
#include "config.h" #include "config.h"
@ -27,7 +26,7 @@
namespace libunwind { namespace libunwind {
/// DwarfInstructions maps abtract dwarf unwind instructions to a particular /// DwarfInstructions maps abtract DWARF unwind instructions to a particular
/// architecture /// architecture
template <typename A, typename R> template <typename A, typename R>
class DwarfInstructions { class DwarfInstructions {
@ -160,15 +159,15 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
&cieInfo) == NULL) { &cieInfo) == NULL) {
PrologInfo prolog; PrologInfo prolog;
if (CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc, if (CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc,
&prolog)) { R::getArch(), &prolog)) {
// get pointer to cfa (architecture specific) // get pointer to cfa (architecture specific)
pint_t cfa = getCFA(addressSpace, prolog, registers); pint_t cfa = getCFA(addressSpace, prolog, registers);
// restore registers that dwarf says were saved // restore registers that DWARF says were saved
R newRegisters = registers; R newRegisters = registers;
pint_t returnAddress = 0; pint_t returnAddress = 0;
const int lastReg = R::lastDwarfRegNum(); const int lastReg = R::lastDwarfRegNum();
assert((int)CFI_Parser<A>::kMaxRegisterNumber > lastReg && assert(static_cast<int>(CFI_Parser<A>::kMaxRegisterNumber) >= lastReg &&
"register range too large"); "register range too large");
assert(lastReg >= (int)cieInfo.returnAddressRegister && assert(lastReg >= (int)cieInfo.returnAddressRegister &&
"register range does not contain return address register"); "register range does not contain return address register");
@ -199,6 +198,42 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
// restoring SP means setting it to CFA. // restoring SP means setting it to CFA.
newRegisters.setSP(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 // Return address is address after call site instruction, so setting IP to
// that does simualates a return. // that does simualates a return.
newRegisters.setIP(returnAddress); newRegisters.setIP(returnAddress);
@ -480,7 +515,7 @@ DwarfInstructions<A, R>::evaluateExpression(pint_t expression, A &addressSpace,
case DW_OP_plus_uconst: case DW_OP_plus_uconst:
// pop stack, add uelb128 constant, push result // pop stack, add uelb128 constant, push result
*sp += addressSpace.getULEB128(p, expressionEnd); *sp += static_cast<pint_t>(addressSpace.getULEB128(p, expressionEnd));
if (log) if (log)
fprintf(stderr, "add constant\n"); fprintf(stderr, "add constant\n");
break; break;
@ -744,7 +779,7 @@ DwarfInstructions<A, R>::evaluateExpression(pint_t expression, A &addressSpace,
case DW_OP_call4: case DW_OP_call4:
case DW_OP_call_ref: case DW_OP_call_ref:
default: default:
_LIBUNWIND_ABORT("dwarf opcode not implemented"); _LIBUNWIND_ABORT("DWARF opcode not implemented");
} }
} }

View File

@ -20,13 +20,14 @@
#include "libunwind.h" #include "libunwind.h"
#include "dwarf2.h" #include "dwarf2.h"
#include "Registers.hpp"
#include "AddressSpace.hpp" #include "config.h"
namespace libunwind { namespace libunwind {
/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records. /// 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 /// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
/// ///
template <typename A> template <typename A>
@ -49,6 +50,9 @@ class CFI_Parser {
bool isSignalFrame; bool isSignalFrame;
bool fdesHaveAugmentationData; bool fdesHaveAugmentationData;
uint8_t returnAddressRegister; uint8_t returnAddressRegister;
#if defined(_LIBUNWIND_TARGET_AARCH64)
bool addressesSignedWithBKey;
#endif
}; };
/// Information about an FDE (Frame Description Entry) /// Information about an FDE (Frame Description Entry)
@ -62,7 +66,7 @@ class CFI_Parser {
}; };
enum { enum {
kMaxRegisterNumber = _LIBUNWIND_MAX_REGISTER kMaxRegisterNumber = _LIBUNWIND_HIGHEST_DWARF_REGISTER
}; };
enum RegisterSavedWhere { enum RegisterSavedWhere {
kRegisterUnused, kRegisterUnused,
@ -77,7 +81,7 @@ class CFI_Parser {
int64_t value; int64_t value;
}; };
/// Information about a frame layout and registers saved determined /// Information about a frame layout and registers saved determined
/// by "running" the dwarf FDE "instructions" /// by "running" the DWARF FDE "instructions"
struct PrologInfo { struct PrologInfo {
uint32_t cfaRegister; uint32_t cfaRegister;
int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
@ -86,7 +90,7 @@ class CFI_Parser {
uint32_t codeOffsetAtStackDecrement; uint32_t codeOffsetAtStackDecrement;
bool registersInOtherRegisters; bool registersInOtherRegisters;
bool sameValueUsed; bool sameValueUsed;
RegisterLocation savedRegisters[kMaxRegisterNumber]; RegisterLocation savedRegisters[kMaxRegisterNumber + 1];
}; };
struct PrologInfoStackEntry { struct PrologInfoStackEntry {
@ -103,7 +107,7 @@ class CFI_Parser {
FDE_Info *fdeInfo, CIE_Info *cieInfo); FDE_Info *fdeInfo, CIE_Info *cieInfo);
static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo, static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
const CIE_Info &cieInfo, pint_t upToPC, 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); 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, static bool parseInstructions(A &addressSpace, pint_t instructions,
pint_t instructionsEnd, const CIE_Info &cieInfo, pint_t instructionsEnd, const CIE_Info &cieInfo,
pint_t pcoffset, pint_t pcoffset,
PrologInfoStackEntry *&rememberStack, PrologInfoStackEntry *&rememberStack, int arch,
PrologInfo *results); PrologInfo *results);
}; };
@ -138,23 +142,23 @@ const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
if (err != NULL) if (err != NULL)
return err; return err;
p += 4; p += 4;
// parse pc begin and range // Parse pc begin and range.
pint_t pcStart = pint_t pcStart =
addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding); addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
pint_t pcRange = pint_t pcRange =
addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F); addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
// parse rest of info // Parse rest of info.
fdeInfo->lsda = 0; fdeInfo->lsda = 0;
// check for augmentation length // Check for augmentation length.
if (cieInfo->fdesHaveAugmentationData) { if (cieInfo->fdesHaveAugmentationData) {
pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI); pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
pint_t endOfAug = p + augLen; pint_t endOfAug = p + augLen;
if (cieInfo->lsdaEncoding != DW_EH_PE_omit) { 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; pint_t lsdaStart = p;
if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) !=
0) { 0) {
// reset pointer and re-parse lsda address // Reset pointer and re-parse LSDA address.
p = lsdaStart; p = lsdaStart;
fdeInfo->lsda = fdeInfo->lsda =
addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
@ -192,23 +196,23 @@ bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
return false; // end marker return false; // end marker
uint32_t id = addressSpace.get32(p); uint32_t id = addressSpace.get32(p);
if (id == 0) { if (id == 0) {
// skip over CIEs // Skip over CIEs.
p += cfiLength; p += cfiLength;
} else { } else {
// process FDE to see if it covers pc // Process FDE to see if it covers pc.
pint_t nextCFI = p + cfiLength; pint_t nextCFI = p + cfiLength;
uint32_t ciePointer = addressSpace.get32(p); uint32_t ciePointer = addressSpace.get32(p);
pint_t cieStart = p - ciePointer; 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 ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) {
if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) { if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) {
p += 4; p += 4;
// parse pc begin and range // Parse pc begin and range.
pint_t pcStart = pint_t pcStart =
addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding); addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
pint_t pcRange = addressSpace.getEncodedP( pint_t pcRange = addressSpace.getEncodedP(
p, nextCFI, cieInfo->pointerEncoding & 0x0F); 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)) { if ((pcStart < pc) && (pc <= pcStart + pcRange)) {
// parse rest of info // parse rest of info
fdeInfo->lsda = 0; fdeInfo->lsda = 0;
@ -217,11 +221,11 @@ bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI); pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
pint_t endOfAug = p + augLen; pint_t endOfAug = p + augLen;
if (cieInfo->lsdaEncoding != DW_EH_PE_omit) { 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; pint_t lsdaStart = p;
if (addressSpace.getEncodedP( if (addressSpace.getEncodedP(
p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) { p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) {
// reset pointer and re-parse lsda address // Reset pointer and re-parse LSDA address.
p = lsdaStart; p = lsdaStart;
fdeInfo->lsda = addressSpace fdeInfo->lsda = addressSpace
.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
@ -239,7 +243,7 @@ bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
// pc is not in begin/range, skip this FDE // pc is not in begin/range, skip this FDE
} }
} else { } else {
// malformed CIE, now augmentation describing pc range encoding // Malformed CIE, now augmentation describing pc range encoding.
} }
} else { } else {
// malformed FDE. CIE is bad // malformed FDE. CIE is bad
@ -263,6 +267,9 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
cieInfo->dataAlignFactor = 0; cieInfo->dataAlignFactor = 0;
cieInfo->isSignalFrame = false; cieInfo->isSignalFrame = false;
cieInfo->fdesHaveAugmentationData = false; cieInfo->fdesHaveAugmentationData = false;
#if defined(_LIBUNWIND_TARGET_AARCH64)
cieInfo->addressesSignedWithBKey = false;
#endif
cieInfo->cieStart = cie; cieInfo->cieStart = cie;
pint_t p = cie; pint_t p = cie;
pint_t cieLength = (pint_t)addressSpace.get32(p); pint_t cieLength = (pint_t)addressSpace.get32(p);
@ -326,6 +333,11 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
case 'S': case 'S':
cieInfo->isSignalFrame = true; cieInfo->isSignalFrame = true;
break; break;
#if defined(_LIBUNWIND_TARGET_AARCH64)
case 'B':
cieInfo->addressesSignedWithBKey = true;
break;
#endif
default: default:
// ignore unknown letters // ignore unknown letters
break; break;
@ -338,12 +350,12 @@ const char *CFI_Parser<A>::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 <typename A> template <typename A>
bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace, bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
const FDE_Info &fdeInfo, const FDE_Info &fdeInfo,
const CIE_Info &cieInfo, pint_t upToPC, const CIE_Info &cieInfo, pint_t upToPC,
PrologInfo *results) { int arch, PrologInfo *results) {
// clear results // clear results
memset(results, '\0', sizeof(PrologInfo)); memset(results, '\0', sizeof(PrologInfo));
PrologInfoStackEntry *rememberStack = NULL; PrologInfoStackEntry *rememberStack = NULL;
@ -351,28 +363,28 @@ bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
// parse CIE then FDE instructions // parse CIE then FDE instructions
return parseInstructions(addressSpace, cieInfo.cieInstructions, return parseInstructions(addressSpace, cieInfo.cieInstructions,
cieInfo.cieStart + cieInfo.cieLength, cieInfo, cieInfo.cieStart + cieInfo.cieLength, cieInfo,
(pint_t)(-1), rememberStack, results) && (pint_t)(-1), rememberStack, arch, results) &&
parseInstructions(addressSpace, fdeInfo.fdeInstructions, parseInstructions(addressSpace, fdeInfo.fdeInstructions,
fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo, 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 <typename A> template <typename A>
bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions, bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
pint_t instructionsEnd, pint_t instructionsEnd,
const CIE_Info &cieInfo, pint_t pcoffset, const CIE_Info &cieInfo, pint_t pcoffset,
PrologInfoStackEntry *&rememberStack, PrologInfoStackEntry *&rememberStack,
PrologInfo *results) { int arch, PrologInfo *results) {
const bool logDwarf = false;
pint_t p = instructions; pint_t p = instructions;
pint_t codeOffset = 0; pint_t codeOffset = 0;
PrologInfo initialState = *results; 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<uint64_t>(instructionsEnd));
// see DWARF Spec, section 6.4.2 for details on unwind opcodes
while ((p < instructionsEnd) && (codeOffset < pcoffset)) { while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
uint64_t reg; uint64_t reg;
uint64_t reg2; uint64_t reg2;
@ -386,81 +398,71 @@ bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
++p; ++p;
switch (opcode) { switch (opcode) {
case DW_CFA_nop: case DW_CFA_nop:
if (logDwarf) _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n");
fprintf(stderr, "DW_CFA_nop\n");
break; break;
case DW_CFA_set_loc: case DW_CFA_set_loc:
codeOffset = codeOffset =
addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding); addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
if (logDwarf) _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n");
fprintf(stderr, "DW_CFA_set_loc\n");
break; break;
case DW_CFA_advance_loc1: case DW_CFA_advance_loc1:
codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor); codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
p += 1; p += 1;
if (logDwarf) _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",
fprintf(stderr, "DW_CFA_advance_loc1: new offset=%" PRIu64 "\n", static_cast<uint64_t>(codeOffset));
(uint64_t)codeOffset);
break; break;
case DW_CFA_advance_loc2: case DW_CFA_advance_loc2:
codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor); codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
p += 2; p += 2;
if (logDwarf) _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",
fprintf(stderr, "DW_CFA_advance_loc2: new offset=%" PRIu64 "\n", static_cast<uint64_t>(codeOffset));
(uint64_t)codeOffset);
break; break;
case DW_CFA_advance_loc4: case DW_CFA_advance_loc4:
codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor); codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
p += 4; p += 4;
if (logDwarf) _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",
fprintf(stderr, "DW_CFA_advance_loc4: new offset=%" PRIu64 "\n", static_cast<uint64_t>(codeOffset));
(uint64_t)codeOffset);
break; break;
case DW_CFA_offset_extended: case DW_CFA_offset_extended:
reg = addressSpace.getULEB128(p, instructionsEnd); reg = addressSpace.getULEB128(p, instructionsEnd);
offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
* cieInfo.dataAlignFactor; * cieInfo.dataAlignFactor;
if (reg > kMaxRegisterNumber) { if (reg > kMaxRegisterNumber) {
fprintf(stderr, _LIBUNWIND_LOG0(
"malformed DW_CFA_offset_extended dwarf unwind, reg too big\n"); "malformed DW_CFA_offset_extended DWARF unwind, reg too big");
return false; return false;
} }
results->savedRegisters[reg].location = kRegisterInCFA; results->savedRegisters[reg].location = kRegisterInCFA;
results->savedRegisters[reg].value = offset; results->savedRegisters[reg].value = offset;
if (logDwarf) _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", "
fprintf(stderr, "offset=%" PRId64 ")\n",
"DW_CFA_offset_extended(reg=%" PRIu64 ", offset=%" PRId64 ")\n", reg, offset);
reg, offset);
break; break;
case DW_CFA_restore_extended: case DW_CFA_restore_extended:
reg = addressSpace.getULEB128(p, instructionsEnd); reg = addressSpace.getULEB128(p, instructionsEnd);
;
if (reg > kMaxRegisterNumber) { if (reg > kMaxRegisterNumber) {
fprintf( _LIBUNWIND_LOG0(
stderr, "malformed DW_CFA_restore_extended DWARF unwind, reg too big");
"malformed DW_CFA_restore_extended dwarf unwind, reg too big\n");
return false; return false;
} }
results->savedRegisters[reg] = initialState.savedRegisters[reg]; results->savedRegisters[reg] = initialState.savedRegisters[reg];
if (logDwarf) _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg);
fprintf(stderr, "DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg);
break; break;
case DW_CFA_undefined: case DW_CFA_undefined:
reg = addressSpace.getULEB128(p, instructionsEnd); reg = addressSpace.getULEB128(p, instructionsEnd);
if (reg > kMaxRegisterNumber) { if (reg > kMaxRegisterNumber) {
fprintf(stderr, _LIBUNWIND_LOG0(
"malformed DW_CFA_undefined dwarf unwind, reg too big\n"); "malformed DW_CFA_undefined DWARF unwind, reg too big");
return false; return false;
} }
results->savedRegisters[reg].location = kRegisterUnused; results->savedRegisters[reg].location = kRegisterUnused;
if (logDwarf) _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
fprintf(stderr, "DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
break; break;
case DW_CFA_same_value: case DW_CFA_same_value:
reg = addressSpace.getULEB128(p, instructionsEnd); reg = addressSpace.getULEB128(p, instructionsEnd);
if (reg > kMaxRegisterNumber) { if (reg > kMaxRegisterNumber) {
fprintf(stderr, _LIBUNWIND_LOG0(
"malformed DW_CFA_same_value dwarf unwind, reg too big\n"); "malformed DW_CFA_same_value DWARF unwind, reg too big");
return false; return false;
} }
// <rdar://problem/8456377> DW_CFA_same_value unsupported // <rdar://problem/8456377> DW_CFA_same_value unsupported
@ -470,29 +472,27 @@ bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
results->savedRegisters[reg].location = kRegisterUnused; results->savedRegisters[reg].location = kRegisterUnused;
// set flag to disable conversion to compact unwind // set flag to disable conversion to compact unwind
results->sameValueUsed = true; results->sameValueUsed = true;
if (logDwarf) _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);
fprintf(stderr, "DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);
break; break;
case DW_CFA_register: case DW_CFA_register:
reg = addressSpace.getULEB128(p, instructionsEnd); reg = addressSpace.getULEB128(p, instructionsEnd);
reg2 = addressSpace.getULEB128(p, instructionsEnd); reg2 = addressSpace.getULEB128(p, instructionsEnd);
if (reg > kMaxRegisterNumber) { if (reg > kMaxRegisterNumber) {
fprintf(stderr, _LIBUNWIND_LOG0(
"malformed DW_CFA_register dwarf unwind, reg too big\n"); "malformed DW_CFA_register DWARF unwind, reg too big");
return false; return false;
} }
if (reg2 > kMaxRegisterNumber) { if (reg2 > kMaxRegisterNumber) {
fprintf(stderr, _LIBUNWIND_LOG0(
"malformed DW_CFA_register dwarf unwind, reg2 too big\n"); "malformed DW_CFA_register DWARF unwind, reg2 too big");
return false; return false;
} }
results->savedRegisters[reg].location = kRegisterInRegister; results->savedRegisters[reg].location = kRegisterInRegister;
results->savedRegisters[reg].value = (int64_t)reg2; results->savedRegisters[reg].value = (int64_t)reg2;
// set flag to disable conversion to compact unwind // set flag to disable conversion to compact unwind
results->registersInOtherRegisters = true; results->registersInOtherRegisters = true;
if (logDwarf) _LIBUNWIND_TRACE_DWARF(
fprintf(stderr, "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2);
reg, reg2);
break; break;
#if !defined(_LIBUNWIND_NO_HEAP) #if !defined(_LIBUNWIND_NO_HEAP)
case DW_CFA_remember_state: case DW_CFA_remember_state:
@ -505,8 +505,7 @@ bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
} else { } else {
return false; return false;
} }
if (logDwarf) _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n");
fprintf(stderr, "DW_CFA_remember_state\n");
break; break;
case DW_CFA_restore_state: case DW_CFA_restore_state:
if (rememberStack != NULL) { if (rememberStack != NULL) {
@ -517,202 +516,243 @@ bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
} else { } else {
return false; return false;
} }
if (logDwarf) _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n");
fprintf(stderr, "DW_CFA_restore_state\n");
break; break;
#endif #endif
case DW_CFA_def_cfa: case DW_CFA_def_cfa:
reg = addressSpace.getULEB128(p, instructionsEnd); reg = addressSpace.getULEB128(p, instructionsEnd);
offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd); offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
if (reg > kMaxRegisterNumber) { 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; return false;
} }
results->cfaRegister = (uint32_t)reg; results->cfaRegister = (uint32_t)reg;
results->cfaRegisterOffset = (int32_t)offset; results->cfaRegisterOffset = (int32_t)offset;
if (logDwarf) _LIBUNWIND_TRACE_DWARF(
fprintf(stderr, "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", reg, offset);
reg, offset);
break; break;
case DW_CFA_def_cfa_register: case DW_CFA_def_cfa_register:
reg = addressSpace.getULEB128(p, instructionsEnd); reg = addressSpace.getULEB128(p, instructionsEnd);
if (reg > kMaxRegisterNumber) { if (reg > kMaxRegisterNumber) {
fprintf( _LIBUNWIND_LOG0(
stderr, "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big");
"malformed DW_CFA_def_cfa_register dwarf unwind, reg too big\n");
return false; return false;
} }
results->cfaRegister = (uint32_t)reg; results->cfaRegister = (uint32_t)reg;
if (logDwarf) _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
fprintf(stderr, "DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
break; break;
case DW_CFA_def_cfa_offset: case DW_CFA_def_cfa_offset:
results->cfaRegisterOffset = (int32_t) results->cfaRegisterOffset = (int32_t)
addressSpace.getULEB128(p, instructionsEnd); addressSpace.getULEB128(p, instructionsEnd);
results->codeOffsetAtStackDecrement = (uint32_t)codeOffset; results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
if (logDwarf) _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n",
fprintf(stderr, "DW_CFA_def_cfa_offset(%d)\n", results->cfaRegisterOffset);
results->cfaRegisterOffset);
break; break;
case DW_CFA_def_cfa_expression: case DW_CFA_def_cfa_expression:
results->cfaRegister = 0; results->cfaRegister = 0;
results->cfaExpression = (int64_t)p; results->cfaExpression = (int64_t)p;
length = addressSpace.getULEB128(p, instructionsEnd); length = addressSpace.getULEB128(p, instructionsEnd);
p += length; assert(length < static_cast<pint_t>(~0) && "pointer overflow");
if (logDwarf) p += static_cast<pint_t>(length);
fprintf(stderr, "DW_CFA_def_cfa_expression(expression=0x%" PRIx64 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64
", length=%" PRIu64 ")\n", ", length=%" PRIu64 ")\n",
results->cfaExpression, length); results->cfaExpression, length);
break; break;
case DW_CFA_expression: case DW_CFA_expression:
reg = addressSpace.getULEB128(p, instructionsEnd); reg = addressSpace.getULEB128(p, instructionsEnd);
if (reg > kMaxRegisterNumber) { if (reg > kMaxRegisterNumber) {
fprintf(stderr, _LIBUNWIND_LOG0(
"malformed DW_CFA_expression dwarf unwind, reg too big\n"); "malformed DW_CFA_expression DWARF unwind, reg too big");
return false; return false;
} }
results->savedRegisters[reg].location = kRegisterAtExpression; results->savedRegisters[reg].location = kRegisterAtExpression;
results->savedRegisters[reg].value = (int64_t)p; results->savedRegisters[reg].value = (int64_t)p;
length = addressSpace.getULEB128(p, instructionsEnd); length = addressSpace.getULEB128(p, instructionsEnd);
p += length; assert(length < static_cast<pint_t>(~0) && "pointer overflow");
if (logDwarf) p += static_cast<pint_t>(length);
fprintf(stderr, "DW_CFA_expression(reg=%" PRIu64 _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", "
", expression=0x%" PRIx64 ", length=%" PRIu64 ")\n", "expression=0x%" PRIx64 ", "
reg, results->savedRegisters[reg].value, length); "length=%" PRIu64 ")\n",
reg, results->savedRegisters[reg].value, length);
break; break;
case DW_CFA_offset_extended_sf: case DW_CFA_offset_extended_sf:
reg = addressSpace.getULEB128(p, instructionsEnd); reg = addressSpace.getULEB128(p, instructionsEnd);
if (reg > kMaxRegisterNumber) { if (reg > kMaxRegisterNumber) {
fprintf( _LIBUNWIND_LOG0(
stderr, "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big");
"malformed DW_CFA_offset_extended_sf dwarf unwind, reg too big\n");
return false; return false;
} }
offset = offset =
addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
results->savedRegisters[reg].location = kRegisterInCFA; results->savedRegisters[reg].location = kRegisterInCFA;
results->savedRegisters[reg].value = offset; results->savedRegisters[reg].value = offset;
if (logDwarf) _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", "
fprintf(stderr, "DW_CFA_offset_extended_sf(reg=%" PRIu64 "offset=%" PRId64 ")\n",
", offset=%" PRId64 ")\n", reg, offset);
reg, offset);
break; break;
case DW_CFA_def_cfa_sf: case DW_CFA_def_cfa_sf:
reg = addressSpace.getULEB128(p, instructionsEnd); reg = addressSpace.getULEB128(p, instructionsEnd);
offset = offset =
addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
if (reg > kMaxRegisterNumber) { if (reg > kMaxRegisterNumber) {
fprintf(stderr, _LIBUNWIND_LOG0(
"malformed DW_CFA_def_cfa_sf dwarf unwind, reg too big\n"); "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big");
return false; return false;
} }
results->cfaRegister = (uint32_t)reg; results->cfaRegister = (uint32_t)reg;
results->cfaRegisterOffset = (int32_t)offset; results->cfaRegisterOffset = (int32_t)offset;
if (logDwarf) _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", "
fprintf(stderr, "offset=%" PRId64 ")\n",
"DW_CFA_def_cfa_sf(reg=%" PRIu64 ", offset=%" PRId64 ")\n", reg, reg, offset);
offset);
break; break;
case DW_CFA_def_cfa_offset_sf: case DW_CFA_def_cfa_offset_sf:
results->cfaRegisterOffset = (int32_t) results->cfaRegisterOffset = (int32_t)
(addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor); (addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor);
results->codeOffsetAtStackDecrement = (uint32_t)codeOffset; results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
if (logDwarf) _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n",
fprintf(stderr, "DW_CFA_def_cfa_offset_sf(%d)\n", results->cfaRegisterOffset);
results->cfaRegisterOffset);
break; break;
case DW_CFA_val_offset: case DW_CFA_val_offset:
reg = addressSpace.getULEB128(p, instructionsEnd); 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) offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
* cieInfo.dataAlignFactor; * cieInfo.dataAlignFactor;
results->savedRegisters[reg].location = kRegisterOffsetFromCFA; results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
results->savedRegisters[reg].value = offset; results->savedRegisters[reg].value = offset;
if (logDwarf) _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "
fprintf(stderr, "offset=%" PRId64 "\n",
"DW_CFA_val_offset(reg=%" PRIu64 ", offset=%" PRId64 "\n", reg, reg, offset);
offset);
break; break;
case DW_CFA_val_offset_sf: case DW_CFA_val_offset_sf:
reg = addressSpace.getULEB128(p, instructionsEnd); reg = addressSpace.getULEB128(p, instructionsEnd);
if (reg > kMaxRegisterNumber) { if (reg > kMaxRegisterNumber) {
fprintf(stderr, _LIBUNWIND_LOG0(
"malformed DW_CFA_val_offset_sf dwarf unwind, reg too big\n"); "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big");
return false; return false;
} }
offset = offset =
addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
results->savedRegisters[reg].location = kRegisterOffsetFromCFA; results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
results->savedRegisters[reg].value = offset; results->savedRegisters[reg].value = offset;
if (logDwarf) _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "
fprintf(stderr, "offset=%" PRId64 "\n",
"DW_CFA_val_offset_sf(reg=%" PRIu64 ", offset=%" PRId64 "\n", reg, offset);
reg, offset);
break; break;
case DW_CFA_val_expression: case DW_CFA_val_expression:
reg = addressSpace.getULEB128(p, instructionsEnd); reg = addressSpace.getULEB128(p, instructionsEnd);
if (reg > kMaxRegisterNumber) { if (reg > kMaxRegisterNumber) {
fprintf(stderr, _LIBUNWIND_LOG0(
"malformed DW_CFA_val_expression dwarf unwind, reg too big\n"); "malformed DW_CFA_val_expression DWARF unwind, reg too big");
return false; return false;
} }
results->savedRegisters[reg].location = kRegisterIsExpression; results->savedRegisters[reg].location = kRegisterIsExpression;
results->savedRegisters[reg].value = (int64_t)p; results->savedRegisters[reg].value = (int64_t)p;
length = addressSpace.getULEB128(p, instructionsEnd); length = addressSpace.getULEB128(p, instructionsEnd);
p += length; assert(length < static_cast<pint_t>(~0) && "pointer overflow");
if (logDwarf) p += static_cast<pint_t>(length);
fprintf(stderr, "DW_CFA_val_expression(reg=%" PRIu64 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "
", expression=0x%" PRIx64 ", length=%" PRIu64 ")\n", "expression=0x%" PRIx64 ", length=%" PRIu64 ")\n",
reg, results->savedRegisters[reg].value, length); reg, results->savedRegisters[reg].value, length);
break; break;
case DW_CFA_GNU_args_size: case DW_CFA_GNU_args_size:
length = addressSpace.getULEB128(p, instructionsEnd); length = addressSpace.getULEB128(p, instructionsEnd);
results->spExtraArgSize = (uint32_t)length; results->spExtraArgSize = (uint32_t)length;
if (logDwarf) _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
fprintf(stderr, "DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
break; break;
case DW_CFA_GNU_negative_offset_extended: case DW_CFA_GNU_negative_offset_extended:
reg = addressSpace.getULEB128(p, instructionsEnd); reg = addressSpace.getULEB128(p, instructionsEnd);
if (reg > kMaxRegisterNumber) { if (reg > kMaxRegisterNumber) {
fprintf(stderr, "malformed DW_CFA_GNU_negative_offset_extended dwarf " _LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF "
"unwind, reg too big\n"); "unwind, reg too big");
return false; return false;
} }
offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
* cieInfo.dataAlignFactor; * cieInfo.dataAlignFactor;
results->savedRegisters[reg].location = kRegisterInCFA; results->savedRegisters[reg].location = kRegisterInCFA;
results->savedRegisters[reg].value = -offset; results->savedRegisters[reg].value = -offset;
if (logDwarf) _LIBUNWIND_TRACE_DWARF(
fprintf(stderr, "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
offset);
break; 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: default:
operand = opcode & 0x3F; operand = opcode & 0x3F;
switch (opcode & 0xC0) { switch (opcode & 0xC0) {
case DW_CFA_offset: case DW_CFA_offset:
reg = operand; 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) offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
* cieInfo.dataAlignFactor; * cieInfo.dataAlignFactor;
results->savedRegisters[reg].location = kRegisterInCFA; results->savedRegisters[reg].location = kRegisterInCFA;
results->savedRegisters[reg].value = offset; results->savedRegisters[reg].value = offset;
if (logDwarf) _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
fprintf(stderr, "DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n", operand, offset);
operand, offset);
break; break;
case DW_CFA_advance_loc: case DW_CFA_advance_loc:
codeOffset += operand * cieInfo.codeAlignFactor; codeOffset += operand * cieInfo.codeAlignFactor;
if (logDwarf) _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
fprintf(stderr, "DW_CFA_advance_loc: new offset=%" PRIu64 "\n", static_cast<uint64_t>(codeOffset));
(uint64_t)codeOffset);
break; break;
case DW_CFA_restore: case DW_CFA_restore:
reg = operand; 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]; results->savedRegisters[reg] = initialState.savedRegisters[reg];
if (logDwarf) _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",
fprintf(stderr, "DW_CFA_restore(reg=%" PRIu64 ")\n", reg); static_cast<uint64_t>(operand));
break; break;
default: default:
if (logDwarf) _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);
fprintf(stderr, "unknown CFA opcode 0x%02X\n", opcode);
return false; return false;
} }
} }

View File

@ -15,7 +15,6 @@
#include "libunwind.h" #include "libunwind.h"
#include "AddressSpace.hpp"
#include "DwarfParser.hpp" #include "DwarfParser.hpp"
namespace libunwind { namespace libunwind {
@ -37,7 +36,7 @@ template <typename A> class EHHeaderParser {
uint8_t table_enc; 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); EHHeaderInfo &ehHdrInfo);
static bool findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart, static bool findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart,
uint32_t sectionLength, uint32_t sectionLength,
@ -54,12 +53,14 @@ template <typename A> class EHHeaderParser {
}; };
template <typename A> template <typename A>
void EHHeaderParser<A>::decodeEHHdr(A &addressSpace, pint_t ehHdrStart, bool EHHeaderParser<A>::decodeEHHdr(A &addressSpace, pint_t ehHdrStart,
pint_t ehHdrEnd, EHHeaderInfo &ehHdrInfo) { pint_t ehHdrEnd, EHHeaderInfo &ehHdrInfo) {
pint_t p = ehHdrStart; pint_t p = ehHdrStart;
uint8_t version = addressSpace.get8(p++); uint8_t version = addressSpace.get8(p++);
if (version != 1) if (version != 1) {
_LIBUNWIND_ABORT("Unsupported .eh_frame_hdr version"); _LIBUNWIND_LOG0("Unsupported .eh_frame_hdr version");
return false;
}
uint8_t eh_frame_ptr_enc = addressSpace.get8(p++); uint8_t eh_frame_ptr_enc = addressSpace.get8(p++);
uint8_t fde_count_enc = addressSpace.get8(p++); uint8_t fde_count_enc = addressSpace.get8(p++);
@ -68,8 +69,12 @@ void EHHeaderParser<A>::decodeEHHdr(A &addressSpace, pint_t ehHdrStart,
ehHdrInfo.eh_frame_ptr = ehHdrInfo.eh_frame_ptr =
addressSpace.getEncodedP(p, ehHdrEnd, eh_frame_ptr_enc, ehHdrStart); addressSpace.getEncodedP(p, ehHdrEnd, eh_frame_ptr_enc, ehHdrStart);
ehHdrInfo.fde_count = 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; ehHdrInfo.table = p;
return true;
} }
template <typename A> template <typename A>
@ -101,7 +106,9 @@ bool EHHeaderParser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart,
pint_t ehHdrEnd = ehHdrStart + sectionLength; pint_t ehHdrEnd = ehHdrStart + sectionLength;
EHHeaderParser<A>::EHHeaderInfo hdrInfo; EHHeaderParser<A>::EHHeaderInfo hdrInfo;
EHHeaderParser<A>::decodeEHHdr(addressSpace, ehHdrStart, ehHdrEnd, hdrInfo); if (!EHHeaderParser<A>::decodeEHHdr(addressSpace, ehHdrStart, ehHdrEnd,
hdrInfo))
return false;
size_t tableEntrySize = getTableEntrySize(hdrInfo.table_enc); size_t tableEntrySize = getTableEntrySize(hdrInfo.table_enc);
pint_t tableEntry; pint_t tableEntry;

View File

@ -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 <windows.h>
#elif !defined(_LIBUNWIND_HAS_NO_THREADS)
#include <pthread.h>
#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__

File diff suppressed because it is too large Load Diff

View File

@ -12,8 +12,9 @@
#include "Unwind-EHABI.h" #include "Unwind-EHABI.h"
#if _LIBUNWIND_ARM_EHABI #if defined(_LIBUNWIND_ARM_EHABI)
#include <inttypes.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
@ -245,11 +246,9 @@ decode_eht_entry(const uint32_t* data, size_t* off, size_t* len) {
return data; return data;
} }
_Unwind_Reason_Code _Unwind_VRS_Interpret( _LIBUNWIND_EXPORT _Unwind_Reason_Code
_Unwind_Context* context, _Unwind_VRS_Interpret(_Unwind_Context *context, const uint32_t *data,
const uint32_t* data, size_t offset, size_t len) {
size_t offset,
size_t len) {
bool wrotePC = false; bool wrotePC = false;
bool finish = false; bool finish = false;
while (offset < len && !finish) { while (offset < len && !finish) {
@ -351,6 +350,7 @@ _Unwind_Reason_Code _Unwind_VRS_Interpret(
} }
case 0xc0: { case 0xc0: {
switch (byte) { switch (byte) {
#if defined(__ARM_WMMX)
case 0xc0: case 0xc0:
case 0xc1: case 0xc1:
case 0xc2: case 0xc2:
@ -378,6 +378,7 @@ _Unwind_Reason_Code _Unwind_VRS_Interpret(
_Unwind_VRS_Pop(context, _UVRSC_WMMXC, v, _UVRSD_DOUBLE); _Unwind_VRS_Pop(context, _UVRSC_WMMXC, v, _UVRSD_DOUBLE);
break; break;
} }
#endif
case 0xc8: case 0xc8:
case 0xc9: { case 0xc9: {
uint8_t v = getByte(data, offset++); uint8_t v = getByte(data, offset++);
@ -416,24 +417,21 @@ _Unwind_Reason_Code _Unwind_VRS_Interpret(
return _URC_CONTINUE_UNWIND; return _URC_CONTINUE_UNWIND;
} }
extern "C" _Unwind_Reason_Code __aeabi_unwind_cpp_pr0( extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code
_Unwind_State state, __aeabi_unwind_cpp_pr0(_Unwind_State state, _Unwind_Control_Block *ucbp,
_Unwind_Control_Block *ucbp, _Unwind_Context *context) {
_Unwind_Context *context) {
return unwindOneFrame(state, ucbp, context); return unwindOneFrame(state, ucbp, context);
} }
extern "C" _Unwind_Reason_Code __aeabi_unwind_cpp_pr1( extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code
_Unwind_State state, __aeabi_unwind_cpp_pr1(_Unwind_State state, _Unwind_Control_Block *ucbp,
_Unwind_Control_Block *ucbp, _Unwind_Context *context) {
_Unwind_Context *context) {
return unwindOneFrame(state, ucbp, context); return unwindOneFrame(state, ucbp, context);
} }
extern "C" _Unwind_Reason_Code __aeabi_unwind_cpp_pr2( extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code
_Unwind_State state, __aeabi_unwind_cpp_pr2(_Unwind_State state, _Unwind_Control_Block *ucbp,
_Unwind_Control_Block *ucbp, _Unwind_Context *context) {
_Unwind_Context *context) {
return unwindOneFrame(state, ucbp, context); return unwindOneFrame(state, ucbp, context);
} }
@ -471,11 +469,11 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
unw_word_t pc; unw_word_t pc;
unw_get_reg(cursor, UNW_REG_IP, &pc); unw_get_reg(cursor, UNW_REG_IP, &pc);
_LIBUNWIND_TRACE_UNWINDING( _LIBUNWIND_TRACE_UNWINDING(
"unwind_phase1(ex_ojb=%p): pc=0x%llX, start_ip=0x%llX, func=%s, " "unwind_phase1(ex_ojb=%p): pc=0x%" PRIxPTR ", start_ip=0x%" PRIxPTR ", func=%s, "
"lsda=0x%llX, personality=0x%llX", "lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR,
static_cast<void *>(exception_object), (long long)pc, static_cast<void *>(exception_object), pc,
(long long)frameInfo.start_ip, functionName, frameInfo.start_ip, functionName,
(long long)frameInfo.lsda, (long long)frameInfo.handler); frameInfo.lsda, frameInfo.handler);
} }
// If there is a personality routine, ask it if it will want to stop at // If there is a personality routine, ask it if it will want to stop at
@ -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)) (frameInfo.start_ip + offset > frameInfo.end_ip))
functionName = ".anonymous."; functionName = ".anonymous.";
_LIBUNWIND_TRACE_UNWINDING( _LIBUNWIND_TRACE_UNWINDING(
"unwind_phase2(ex_ojb=%p): start_ip=0x%llX, func=%s, sp=0x%llX, " "unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIxPTR ", func=%s, sp=0x%" PRIxPTR ", "
"lsda=0x%llX, personality=0x%llX", "lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR "",
static_cast<void *>(exception_object), (long long)frameInfo.start_ip, static_cast<void *>(exception_object), frameInfo.start_ip,
functionName, (long long)sp, (long long)frameInfo.lsda, functionName, sp, frameInfo.lsda,
(long long)frameInfo.handler); frameInfo.handler);
} }
// If there is a personality routine, tell it we are unwinding. // If there is a personality routine, tell it we are unwinding.
@ -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_IP, &pc);
unw_get_reg(cursor, UNW_REG_SP, &sp); unw_get_reg(cursor, UNW_REG_SP, &sp);
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering " _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering "
"user code with ip=0x%llX, sp=0x%llX", "user code with ip=0x%" PRIxPTR ", sp=0x%" PRIxPTR,
static_cast<void *>(exception_object), static_cast<void *>(exception_object),
(long long)pc, (long long)sp); pc, sp);
} }
{ {
@ -753,7 +751,7 @@ static uint64_t ValueAsBitPattern(_Unwind_VRS_DataRepresentation representation,
return value; return value;
} }
_Unwind_VRS_Result _LIBUNWIND_EXPORT _Unwind_VRS_Result
_Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, _Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
uint32_t regno, _Unwind_VRS_DataRepresentation representation, uint32_t regno, _Unwind_VRS_DataRepresentation representation,
void *valuep) { void *valuep) {
@ -771,13 +769,6 @@ _Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
*(unw_word_t *)valuep) == UNW_ESUCCESS *(unw_word_t *)valuep) == UNW_ESUCCESS
? _UVRSR_OK ? _UVRSR_OK
: _UVRSR_FAILED; : _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: case _UVRSC_VFP:
if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE)
return _UVRSR_FAILED; return _UVRSR_FAILED;
@ -794,6 +785,14 @@ _Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
*(unw_fpreg_t *)valuep) == UNW_ESUCCESS *(unw_fpreg_t *)valuep) == UNW_ESUCCESS
? _UVRSR_OK ? _UVRSR_OK
: _UVRSR_FAILED; : _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: case _UVRSC_WMMXD:
if (representation != _UVRSD_DOUBLE || regno > 31) if (representation != _UVRSD_DOUBLE || regno > 31)
return _UVRSR_FAILED; return _UVRSR_FAILED;
@ -801,6 +800,11 @@ _Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
*(unw_fpreg_t *)valuep) == UNW_ESUCCESS *(unw_fpreg_t *)valuep) == UNW_ESUCCESS
? _UVRSR_OK ? _UVRSR_OK
: _UVRSR_FAILED; : _UVRSR_FAILED;
#else
case _UVRSC_WMMXC:
case _UVRSC_WMMXD:
break;
#endif
} }
_LIBUNWIND_ABORT("unsupported register class"); _LIBUNWIND_ABORT("unsupported register class");
} }
@ -819,13 +823,6 @@ _Unwind_VRS_Get_Internal(_Unwind_Context *context,
(unw_word_t *)valuep) == UNW_ESUCCESS (unw_word_t *)valuep) == UNW_ESUCCESS
? _UVRSR_OK ? _UVRSR_OK
: _UVRSR_FAILED; : _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: case _UVRSC_VFP:
if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE)
return _UVRSR_FAILED; return _UVRSR_FAILED;
@ -842,6 +839,14 @@ _Unwind_VRS_Get_Internal(_Unwind_Context *context,
(unw_fpreg_t *)valuep) == UNW_ESUCCESS (unw_fpreg_t *)valuep) == UNW_ESUCCESS
? _UVRSR_OK ? _UVRSR_OK
: _UVRSR_FAILED; : _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: case _UVRSC_WMMXD:
if (representation != _UVRSD_DOUBLE || regno > 31) if (representation != _UVRSD_DOUBLE || regno > 31)
return _UVRSR_FAILED; return _UVRSR_FAILED;
@ -849,16 +854,19 @@ _Unwind_VRS_Get_Internal(_Unwind_Context *context,
(unw_fpreg_t *)valuep) == UNW_ESUCCESS (unw_fpreg_t *)valuep) == UNW_ESUCCESS
? _UVRSR_OK ? _UVRSR_OK
: _UVRSR_FAILED; : _UVRSR_FAILED;
#else
case _UVRSC_WMMXC:
case _UVRSC_WMMXD:
break;
#endif
} }
_LIBUNWIND_ABORT("unsupported register class"); _LIBUNWIND_ABORT("unsupported register class");
} }
_Unwind_VRS_Result _Unwind_VRS_Get( _LIBUNWIND_EXPORT _Unwind_VRS_Result
_Unwind_Context *context, _Unwind_VRS_Get(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
_Unwind_VRS_RegClass regclass, uint32_t regno, _Unwind_VRS_DataRepresentation representation,
uint32_t regno, void *valuep) {
_Unwind_VRS_DataRepresentation representation,
void *valuep) {
_Unwind_VRS_Result result = _Unwind_VRS_Result result =
_Unwind_VRS_Get_Internal(context, regclass, regno, representation, _Unwind_VRS_Get_Internal(context, regclass, regno, representation,
valuep); valuep);
@ -879,8 +887,11 @@ _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
static_cast<void *>(context), regclass, discriminator, static_cast<void *>(context), regclass, discriminator,
representation); representation);
switch (regclass) { switch (regclass) {
case _UVRSC_CORE: case _UVRSC_WMMXC:
case _UVRSC_WMMXC: { #if !defined(__ARM_WMMX)
break;
#endif
case _UVRSC_CORE: {
if (representation != _UVRSD_UINT32) if (representation != _UVRSD_UINT32)
return _UVRSR_FAILED; return _UVRSR_FAILED;
// When popping SP from the stack, we don't want to override it from the // 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; 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) if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE)
return _UVRSR_FAILED; return _UVRSR_FAILED;
uint32_t first = discriminator >> 16; uint32_t first = discriminator >> 16;
@ -974,4 +988,4 @@ __gnu_unwind_frame(_Unwind_Exception *exception_object,
return _URC_OK; return _URC_OK;
} }
#endif // _LIBUNWIND_ARM_EHABI #endif // defined(_LIBUNWIND_ARM_EHABI)

View File

@ -13,7 +13,7 @@
#include <__libunwind_config.h> #include <__libunwind_config.h>
#if _LIBUNWIND_ARM_EHABI #if defined(_LIBUNWIND_ARM_EHABI)
#include <stdint.h> #include <stdint.h>
#include <unwind.h> #include <unwind.h>
@ -46,6 +46,6 @@ extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr2(
} // extern "C" } // extern "C"
#endif #endif
#endif // _LIBUNWIND_ARM_EHABI #endif // defined(_LIBUNWIND_ARM_EHABI)
#endif // __UNWIND_EHABI_H__ #endif // __UNWIND_EHABI_H__

View File

@ -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 <unwind.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <windef.h>
#include <excpt.h>
#include <winnt.h>
#include <ntstatus.h>
#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<LocalAddressSpace, Registers_x86_64>(
context, LocalAddressSpace::sThisAddressSpace);
auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor);
co->setInfoBasedOnIPRegister();
return UNW_ESUCCESS;
#elif defined(_LIBUNWIND_TARGET_ARM)
new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_arm>(
context, LocalAddressSpace::sThisAddressSpace);
auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor);
co->setInfoBasedOnIPRegister();
return UNW_ESUCCESS;
#elif defined(_LIBUNWIND_TARGET_AARCH64)
new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_arm64>(
context, LocalAddressSpace::sThisAddressSpace);
auto *co = reinterpret_cast<AbstractUnwindCursor *>(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<UnwindCursor<LocalAddressSpace, Registers_x86_64> *>(cursor)->getDispatcherContext();
#elif defined(_LIBUNWIND_TARGET_ARM)
return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm> *>(cursor)->getDispatcherContext();
#elif defined(_LIBUNWIND_TARGET_AARCH64)
return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm64> *>(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<UnwindCursor<LocalAddressSpace, Registers_x86_64> *>(cursor)->setDispatcherContext(disp);
#elif defined(_LIBUNWIND_TARGET_ARM)
reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm> *>(cursor)->setDispatcherContext(disp);
#elif defined(_LIBUNWIND_TARGET_AARCH64)
reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm64> *>(cursor)->setDispatcherContext(disp);
#endif
}
#endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)

View File

@ -17,32 +17,26 @@
#include <stdlib.h> #include <stdlib.h>
#include "config.h" #include "config.h"
#include "unwind_ext.h"
// /// With SJLJ based exceptions, any function that has a catch clause or needs to
// 32-bit iOS uses setjump/longjump based C++ exceptions. /// do any clean up when an exception propagates through it, needs to call
// Other architectures use "zero cost" exceptions. /// \c _Unwind_SjLj_Register at the start of the function and
// /// \c _Unwind_SjLj_Unregister at the end. The register function is called with
// With SJLJ based exceptions, any function that has a catch clause or needs to /// the address of a block of memory in the function's stack frame. The runtime
// do any clean up when an exception propagates through it, needs to call /// keeps a linked list (stack) of these blocks - one per thread. The calling
// _Unwind_SjLj_Register() at the start of the function and /// function also sets the personality and lsda fields of the block.
// _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 { struct _Unwind_FunctionContext {
// next function in stack of handlers // next function in stack of handlers
struct _Unwind_FunctionContext *prev; struct _Unwind_FunctionContext *prev;
// set by calling function before registering to be the landing pad // 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 // 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 // set by calling function before registering
__personality_routine personality; // arm offset=24 __personality_routine personality; // arm offset=24
@ -53,6 +47,48 @@ struct _Unwind_FunctionContext {
void *jbuf[]; 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 <System/pthread_machdep.h>
#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 /// Called at start of each function that catches exceptions
_LIBUNWIND_EXPORT void _LIBUNWIND_EXPORT void
@ -465,4 +501,4 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) {
return 0; return 0;
} }
#endif // _LIBUNWIND_BUILD_SJLJ_APIS #endif // defined(_LIBUNWIND_BUILD_SJLJ_APIS)

View File

@ -16,13 +16,53 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <pthread.h>
#include <unwind.h> #include <unwind.h>
#ifdef _WIN32
#include <windows.h>
#include <ntverp.h>
#endif
#ifdef __APPLE__ #ifdef __APPLE__
#include <mach-o/dyld.h> #include <mach-o/dyld.h>
#endif #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 "config.h"
#include "AddressSpace.hpp" #include "AddressSpace.hpp"
@ -32,11 +72,12 @@
#include "EHHeaderParser.hpp" #include "EHHeaderParser.hpp"
#include "libunwind.h" #include "libunwind.h"
#include "Registers.hpp" #include "Registers.hpp"
#include "RWMutex.hpp"
#include "Unwind-EHABI.h" #include "Unwind-EHABI.h"
namespace libunwind { namespace libunwind {
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
/// Cache of recently found FDEs. /// Cache of recently found FDEs.
template <typename A> template <typename A>
class _LIBUNWIND_HIDDEN DwarfFDECache { class _LIBUNWIND_HIDDEN DwarfFDECache {
@ -60,7 +101,7 @@ class _LIBUNWIND_HIDDEN DwarfFDECache {
// These fields are all static to avoid needing an initializer. // These fields are all static to avoid needing an initializer.
// There is only one instance of this class per process. // There is only one instance of this class per process.
static pthread_rwlock_t _lock; static RWMutex _lock;
#ifdef __APPLE__ #ifdef __APPLE__
static void dyldUnloadHook(const struct mach_header *mh, intptr_t slide); static void dyldUnloadHook(const struct mach_header *mh, intptr_t slide);
static bool _registeredForDyldUnloads; static bool _registeredForDyldUnloads;
@ -88,7 +129,7 @@ template <typename A>
typename DwarfFDECache<A>::entry DwarfFDECache<A>::_initialBuffer[64]; typename DwarfFDECache<A>::entry DwarfFDECache<A>::_initialBuffer[64];
template <typename A> template <typename A>
pthread_rwlock_t DwarfFDECache<A>::_lock = PTHREAD_RWLOCK_INITIALIZER; RWMutex DwarfFDECache<A>::_lock;
#ifdef __APPLE__ #ifdef __APPLE__
template <typename A> template <typename A>
@ -98,7 +139,7 @@ bool DwarfFDECache<A>::_registeredForDyldUnloads = false;
template <typename A> template <typename A>
typename A::pint_t DwarfFDECache<A>::findFDE(pint_t mh, pint_t pc) { typename A::pint_t DwarfFDECache<A>::findFDE(pint_t mh, pint_t pc) {
pint_t result = 0; 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) { for (entry *p = _buffer; p < _bufferUsed; ++p) {
if ((mh == p->mh) || (mh == 0)) { if ((mh == p->mh) || (mh == 0)) {
if ((p->ip_start <= pc) && (pc < p->ip_end)) { if ((p->ip_start <= pc) && (pc < p->ip_end)) {
@ -107,7 +148,7 @@ typename A::pint_t DwarfFDECache<A>::findFDE(pint_t mh, pint_t pc) {
} }
} }
} }
_LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock)); _LIBUNWIND_LOG_IF_FALSE(_lock.unlock_shared());
return result; return result;
} }
@ -115,7 +156,7 @@ template <typename A>
void DwarfFDECache<A>::add(pint_t mh, pint_t ip_start, pint_t ip_end, void DwarfFDECache<A>::add(pint_t mh, pint_t ip_start, pint_t ip_end,
pint_t fde) { pint_t fde) {
#if !defined(_LIBUNWIND_NO_HEAP) #if !defined(_LIBUNWIND_NO_HEAP)
_LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock)); _LIBUNWIND_LOG_IF_FALSE(_lock.lock());
if (_bufferUsed >= _bufferEnd) { if (_bufferUsed >= _bufferEnd) {
size_t oldSize = (size_t)(_bufferEnd - _buffer); size_t oldSize = (size_t)(_bufferEnd - _buffer);
size_t newSize = oldSize * 4; size_t newSize = oldSize * 4;
@ -139,13 +180,13 @@ void DwarfFDECache<A>::add(pint_t mh, pint_t ip_start, pint_t ip_end,
_registeredForDyldUnloads = true; _registeredForDyldUnloads = true;
} }
#endif #endif
_LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock)); _LIBUNWIND_LOG_IF_FALSE(_lock.unlock());
#endif #endif
} }
template <typename A> template <typename A>
void DwarfFDECache<A>::removeAllIn(pint_t mh) { void DwarfFDECache<A>::removeAllIn(pint_t mh) {
_LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock)); _LIBUNWIND_LOG_IF_FALSE(_lock.lock());
entry *d = _buffer; entry *d = _buffer;
for (const entry *s = _buffer; s < _bufferUsed; ++s) { for (const entry *s = _buffer; s < _bufferUsed; ++s) {
if (s->mh != mh) { if (s->mh != mh) {
@ -155,7 +196,7 @@ void DwarfFDECache<A>::removeAllIn(pint_t mh) {
} }
} }
_bufferUsed = d; _bufferUsed = d;
_LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock)); _LIBUNWIND_LOG_IF_FALSE(_lock.unlock());
} }
#ifdef __APPLE__ #ifdef __APPLE__
@ -168,18 +209,18 @@ void DwarfFDECache<A>::dyldUnloadHook(const struct mach_header *mh, intptr_t ) {
template <typename A> template <typename A>
void DwarfFDECache<A>::iterateCacheEntries(void (*func)( void DwarfFDECache<A>::iterateCacheEntries(void (*func)(
unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) { 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) { for (entry *p = _buffer; p < _bufferUsed; ++p) {
(*func)(p->ip_start, p->ip_end, p->fde, p->mh); (*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)) #define arrayoffsetof(type, index, field) ((size_t)(&((type *)0)[index].field))
#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
template <typename A> class UnwindSectionHeader { template <typename A> class UnwindSectionHeader {
public: public:
UnwindSectionHeader(A &addressSpace, typename A::pint_t addr) UnwindSectionHeader(A &addressSpace, typename A::pint_t addr)
@ -367,7 +408,7 @@ template <typename A> class UnwindSectionLsdaArray {
A &_addressSpace; A &_addressSpace;
typename A::pint_t _addr; typename A::pint_t _addr;
}; };
#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND #endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
class _LIBUNWIND_HIDDEN AbstractUnwindCursor { class _LIBUNWIND_HIDDEN AbstractUnwindCursor {
public: public:
@ -412,6 +453,419 @@ class _LIBUNWIND_HIDDEN AbstractUnwindCursor {
#endif #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 <typename A, typename R>
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<unw_word_t>(_dispContext.HandlerData);
if (_dispContext.LanguageHandler) {
_info.handler = reinterpret_cast<unw_word_t>(__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 <typename A, typename R>
UnwindCursor<A, R>::UnwindCursor(unw_context_t *context, A &as)
: _addressSpace(as), _unwindInfoMissing(false) {
static_assert((check_fit<UnwindCursor<A, R>, 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 <typename A, typename R>
UnwindCursor<A, R>::UnwindCursor(CONTEXT *context, A &as)
: _addressSpace(as), _unwindInfoMissing(false) {
static_assert((check_fit<UnwindCursor<A, R>, 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 <typename A, typename R>
bool UnwindCursor<A, R>::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 <typename A, typename R>
unw_word_t UnwindCursor<A, R>::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 <typename A, typename R>
void UnwindCursor<A, R>::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 <typename A, typename R>
bool UnwindCursor<A, R>::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 <typename A, typename R>
unw_fpreg_t UnwindCursor<A, R>::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 <typename A, typename R>
void UnwindCursor<A, R>::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 <typename A, typename R> void UnwindCursor<A, R>::jumpto() {
RtlRestoreContext(&_msContext, nullptr);
}
#ifdef __arm__
template <typename A, typename R> void UnwindCursor<A, R>::saveVFPAsX() {}
#endif
template <typename A, typename R>
const char *UnwindCursor<A, R>::getRegisterName(int regNum) {
return R::getRegisterName(regNum);
}
template <typename A, typename R> bool UnwindCursor<A, R>::isSignalFrame() {
return false;
}
#else // !defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) || !defined(_WIN32)
/// UnwindCursor contains all state (including all register values) during /// UnwindCursor contains all state (including all register values) during
/// an unwind. This is normally stack allocated inside a unw_cursor_t. /// an unwind. This is normally stack allocated inside a unw_cursor_t.
template <typename A, typename R> template <typename A, typename R>
@ -440,7 +894,7 @@ class UnwindCursor : public AbstractUnwindCursor{
private: private:
#if _LIBUNWIND_ARM_EHABI #if defined(_LIBUNWIND_ARM_EHABI)
bool getInfoFromEHABISection(pint_t pc, const UnwindInfoSections &sects); bool getInfoFromEHABISection(pint_t pc, const UnwindInfoSections &sects);
int stepWithEHABI() { int stepWithEHABI() {
@ -458,7 +912,7 @@ class UnwindCursor : public AbstractUnwindCursor{
} }
#endif #endif
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
bool getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections &sects, bool getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections &sects,
uint32_t fdeSectionOffsetHint=0); uint32_t fdeSectionOffsetHint=0);
int stepWithDwarfFDE() { int stepWithDwarfFDE() {
@ -469,11 +923,11 @@ class UnwindCursor : public AbstractUnwindCursor{
} }
#endif #endif
#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
bool getInfoFromCompactEncodingSection(pint_t pc, bool getInfoFromCompactEncodingSection(pint_t pc,
const UnwindInfoSections &sects); const UnwindInfoSections &sects);
int stepWithCompactEncoding() { int stepWithCompactEncoding() {
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
if ( compactSaysUseDwarf() ) if ( compactSaysUseDwarf() )
return stepWithDwarfFDE(); return stepWithDwarfFDE();
#endif #endif
@ -501,6 +955,13 @@ class UnwindCursor : public AbstractUnwindCursor{
} }
#endif #endif
#if defined(_LIBUNWIND_TARGET_PPC64)
int stepWithCompactEncoding(Registers_ppc64 &) {
return UNW_EINVAL;
}
#endif
#if defined(_LIBUNWIND_TARGET_AARCH64) #if defined(_LIBUNWIND_TARGET_AARCH64)
int stepWithCompactEncoding(Registers_arm64 &) { int stepWithCompactEncoding(Registers_arm64 &) {
return CompactUnwinder_arm64<A>::stepWithCompactEncoding( return CompactUnwinder_arm64<A>::stepWithCompactEncoding(
@ -520,6 +981,10 @@ class UnwindCursor : public AbstractUnwindCursor{
} }
#endif #endif
#if defined(_LIBUNWIND_TARGET_SPARC)
int stepWithCompactEncoding(Registers_sparc &) { return UNW_EINVAL; }
#endif
bool compactSaysUseDwarf(uint32_t *offset=NULL) const { bool compactSaysUseDwarf(uint32_t *offset=NULL) const {
R dummy; R dummy;
return compactSaysUseDwarf(dummy, offset); return compactSaysUseDwarf(dummy, offset);
@ -553,6 +1018,12 @@ class UnwindCursor : public AbstractUnwindCursor{
} }
#endif #endif
#if defined(_LIBUNWIND_TARGET_PPC64)
bool compactSaysUseDwarf(Registers_ppc64 &, uint32_t *) const {
return true;
}
#endif
#if defined(_LIBUNWIND_TARGET_AARCH64) #if defined(_LIBUNWIND_TARGET_AARCH64)
bool compactSaysUseDwarf(Registers_arm64 &, uint32_t *offset) const { bool compactSaysUseDwarf(Registers_arm64 &, uint32_t *offset) const {
if ((_info.format & UNWIND_ARM64_MODE_MASK) == UNWIND_ARM64_MODE_DWARF) { if ((_info.format & UNWIND_ARM64_MODE_MASK) == UNWIND_ARM64_MODE_DWARF) {
@ -575,9 +1046,14 @@ class UnwindCursor : public AbstractUnwindCursor{
return true; return true;
} }
#endif #endif
#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND #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 { compact_unwind_encoding_t dwarfEncoding() const {
R dummy; R dummy;
return dwarfEncoding(dummy); return dwarfEncoding(dummy);
@ -601,12 +1077,24 @@ class UnwindCursor : public AbstractUnwindCursor{
} }
#endif #endif
#if defined(_LIBUNWIND_TARGET_PPC64)
compact_unwind_encoding_t dwarfEncoding(Registers_ppc64 &) const {
return 0;
}
#endif
#if defined(_LIBUNWIND_TARGET_AARCH64) #if defined(_LIBUNWIND_TARGET_AARCH64)
compact_unwind_encoding_t dwarfEncoding(Registers_arm64 &) const { compact_unwind_encoding_t dwarfEncoding(Registers_arm64 &) const {
return UNWIND_ARM64_MODE_DWARF; return UNWIND_ARM64_MODE_DWARF;
} }
#endif #endif
#if defined(_LIBUNWIND_TARGET_ARM)
compact_unwind_encoding_t dwarfEncoding(Registers_arm &) const {
return 0;
}
#endif
#if defined (_LIBUNWIND_TARGET_OR1K) #if defined (_LIBUNWIND_TARGET_OR1K)
compact_unwind_encoding_t dwarfEncoding(Registers_or1k &) const { compact_unwind_encoding_t dwarfEncoding(Registers_or1k &) const {
return 0; return 0;
@ -630,7 +1118,26 @@ class UnwindCursor : public AbstractUnwindCursor{
return 0; return 0;
} }
#endif #endif
#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND
#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; A &_addressSpace;
@ -708,7 +1215,9 @@ template <typename A, typename R> bool UnwindCursor<A, R>::isSignalFrame() {
return _isSignalFrame; return _isSignalFrame;
} }
#if _LIBUNWIND_ARM_EHABI #endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
#if defined(_LIBUNWIND_ARM_EHABI)
struct EHABIIndexEntry { struct EHABIIndexEntry {
uint32_t functionOffset; uint32_t functionOffset;
uint32_t data; uint32_t data;
@ -729,7 +1238,8 @@ struct EHABISectionIterator {
return _Self(addressSpace, sects, 0); return _Self(addressSpace, sects, 0);
} }
static _Self end(A& addressSpace, const UnwindInfoSections& sects) { 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) EHABISectionIterator(A& addressSpace, const UnwindInfoSections& sects, size_t i)
@ -779,14 +1289,21 @@ bool UnwindCursor<A, R>::getInfoFromEHABISection(
EHABISectionIterator<A>::begin(_addressSpace, sects); EHABISectionIterator<A>::begin(_addressSpace, sects);
EHABISectionIterator<A> end = EHABISectionIterator<A> end =
EHABISectionIterator<A>::end(_addressSpace, sects); EHABISectionIterator<A>::end(_addressSpace, sects);
if (begin == end)
return false;
EHABISectionIterator<A> itNextPC = std::upper_bound(begin, end, pc); EHABISectionIterator<A> itNextPC = std::upper_bound(begin, end, pc);
if (itNextPC == begin || itNextPC == end) if (itNextPC == begin)
return false; return false;
EHABISectionIterator<A> itThisPC = itNextPC - 1; EHABISectionIterator<A> itThisPC = itNextPC - 1;
pint_t thisPC = itThisPC.functionAddress(); 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<pint_t>::max()
: itNextPC.functionAddress();
pint_t indexDataAddr = itThisPC.dataAddress(); pint_t indexDataAddr = itThisPC.dataAddress();
if (indexDataAddr == 0) if (indexDataAddr == 0)
@ -903,7 +1420,7 @@ bool UnwindCursor<A, R>::getInfoFromEHABISection(
} }
#endif #endif
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
template <typename A, typename R> template <typename A, typename R>
bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc, bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
const UnwindInfoSections &sects, const UnwindInfoSections &sects,
@ -919,7 +1436,7 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
sects.dwarf_section + fdeSectionOffsetHint, sects.dwarf_section + fdeSectionOffsetHint,
&fdeInfo, &cieInfo); &fdeInfo, &cieInfo);
} }
#if _LIBUNWIND_SUPPORT_DWARF_INDEX #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
if (!foundFDE && (sects.dwarf_index_section != 0)) { if (!foundFDE && (sects.dwarf_index_section != 0)) {
foundFDE = EHHeaderParser<A>::findFDE( foundFDE = EHHeaderParser<A>::findFDE(
_addressSpace, pc, sects.dwarf_index_section, _addressSpace, pc, sects.dwarf_index_section,
@ -946,7 +1463,7 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
if (foundFDE) { if (foundFDE) {
typename CFI_Parser<A>::PrologInfo prolog; typename CFI_Parser<A>::PrologInfo prolog;
if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc, if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc,
&prolog)) { R::getArch(), &prolog)) {
// Save off parsed FDE info // Save off parsed FDE info
_info.start_ip = fdeInfo.pcStart; _info.start_ip = fdeInfo.pcStart;
_info.end_ip = fdeInfo.pcEnd; _info.end_ip = fdeInfo.pcEnd;
@ -962,7 +1479,7 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
// Add to cache (to make next lookup faster) if we had no hint // Add to cache (to make next lookup faster) if we had no hint
// and there was no index. // and there was no index.
if (!foundInCache && (fdeSectionOffsetHint == 0)) { if (!foundInCache && (fdeSectionOffsetHint == 0)) {
#if _LIBUNWIND_SUPPORT_DWARF_INDEX #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
if (sects.dwarf_index_section == 0) if (sects.dwarf_index_section == 0)
#endif #endif
DwarfFDECache<A>::add(sects.dso_base, fdeInfo.pcStart, fdeInfo.pcEnd, DwarfFDECache<A>::add(sects.dso_base, fdeInfo.pcStart, fdeInfo.pcEnd,
@ -974,10 +1491,10 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
//_LIBUNWIND_DEBUG_LOG("can't find/use FDE for pc=0x%llX", (uint64_t)pc); //_LIBUNWIND_DEBUG_LOG("can't find/use FDE for pc=0x%llX", (uint64_t)pc);
return false; 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 <typename A, typename R> template <typename A, typename R>
bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(pint_t pc, bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(pint_t pc,
const UnwindInfoSections &sects) { const UnwindInfoSections &sects) {
@ -1231,13 +1748,62 @@ bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(pint_t pc,
_info.extra = sects.dso_base; _info.extra = sects.dso_base;
return true; return true;
} }
#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND #endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
template <typename A, typename R>
bool UnwindCursor<A, R>::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<unw_word_t>(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<UNWIND_INFO *>(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<uint32_t *>(&xdata->UnwindCodes[lastcode]);
_info.lsda = reinterpret_cast<unw_word_t>(handler+1);
if (*handler) {
_info.handler = reinterpret_cast<unw_word_t>(__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 <typename A, typename R> template <typename A, typename R>
void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) { void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
pint_t pc = (pint_t)this->getReg(UNW_REG_IP); 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. // Remove the thumb bit so the IP represents the actual instruction address.
// This matches the behaviour of _Unwind_GetIP on arm. // This matches the behaviour of _Unwind_GetIP on arm.
pc &= (pint_t)~0x1; pc &= (pint_t)~0x1;
@ -1254,11 +1820,11 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
// Ask address space object to find unwind sections for this pc. // Ask address space object to find unwind sections for this pc.
UnwindInfoSections sects; UnwindInfoSections sects;
if (_addressSpace.findUnwindSections(pc, 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 there is a compact unwind encoding table, look there first.
if (sects.compact_unwind_section != 0) { if (sects.compact_unwind_section != 0) {
if (this->getInfoFromCompactEncodingSection(pc, sects)) { 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. // Found info in table, done unless encoding says to use dwarf.
uint32_t dwarfOffset; uint32_t dwarfOffset;
if ((sects.dwarf_section != 0) && compactSaysUseDwarf(&dwarfOffset)) { if ((sects.dwarf_section != 0) && compactSaysUseDwarf(&dwarfOffset)) {
@ -1275,9 +1841,15 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
return; 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 there is dwarf unwind info, look there next.
if (sects.dwarf_section != 0) { if (sects.dwarf_section != 0) {
if (this->getInfoFromDwarfSection(pc, sects)) { if (this->getInfoFromDwarfSection(pc, sects)) {
@ -1287,14 +1859,14 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
} }
#endif #endif
#if _LIBUNWIND_ARM_EHABI #if defined(_LIBUNWIND_ARM_EHABI)
// If there is ARM EHABI unwind info, look there next. // If there is ARM EHABI unwind info, look there next.
if (sects.arm_section != 0 && this->getInfoFromEHABISection(pc, sects)) if (sects.arm_section != 0 && this->getInfoFromEHABISection(pc, sects))
return; return;
#endif #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 // There is no static unwind info for this pc. Look to see if an FDE was
// dynamically registered for it. // dynamically registered for it.
pint_t cachedFDE = DwarfFDECache<A>::findFDE(0, pc); pint_t cachedFDE = DwarfFDECache<A>::findFDE(0, pc);
@ -1306,7 +1878,7 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
if (msg == NULL) { if (msg == NULL) {
typename CFI_Parser<A>::PrologInfo prolog; typename CFI_Parser<A>::PrologInfo prolog;
if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo,
pc, &prolog)) { pc, R::getArch(), &prolog)) {
// save off parsed FDE info // save off parsed FDE info
_info.start_ip = fdeInfo.pcStart; _info.start_ip = fdeInfo.pcStart;
_info.end_ip = fdeInfo.pcEnd; _info.end_ip = fdeInfo.pcEnd;
@ -1335,8 +1907,8 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
// Double check this FDE is for a function that includes the pc. // Double check this FDE is for a function that includes the pc.
if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd)) { if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd)) {
typename CFI_Parser<A>::PrologInfo prolog; typename CFI_Parser<A>::PrologInfo prolog;
if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo,
cieInfo, pc, &prolog)) { pc, R::getArch(), &prolog)) {
// save off parsed FDE info // save off parsed FDE info
_info.start_ip = fdeInfo.pcStart; _info.start_ip = fdeInfo.pcStart;
_info.end_ip = fdeInfo.pcEnd; _info.end_ip = fdeInfo.pcEnd;
@ -1353,7 +1925,7 @@ void UnwindCursor<A, R>::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 // no unwind info, flag that we can't reliably unwind
_unwindInfoMissing = true; _unwindInfoMissing = true;
@ -1367,14 +1939,17 @@ int UnwindCursor<A, R>::step() {
// Use unwinding info to modify register set as if function returned. // Use unwinding info to modify register set as if function returned.
int result; int result;
#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
result = this->stepWithCompactEncoding(); 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(); result = this->stepWithDwarfFDE();
#elif _LIBUNWIND_ARM_EHABI #elif defined(_LIBUNWIND_ARM_EHABI)
result = this->stepWithEHABI(); result = this->stepWithEHABI();
#else #else
#error Need _LIBUNWIND_SUPPORT_COMPACT_UNWIND or \ #error Need _LIBUNWIND_SUPPORT_COMPACT_UNWIND or \
_LIBUNWIND_SUPPORT_SEH_UNWIND or \
_LIBUNWIND_SUPPORT_DWARF_UNWIND or \ _LIBUNWIND_SUPPORT_DWARF_UNWIND or \
_LIBUNWIND_ARM_EHABI _LIBUNWIND_ARM_EHABI
#endif #endif
@ -1384,8 +1959,6 @@ int UnwindCursor<A, R>::step() {
this->setInfoBasedOnIPRegister(true); this->setInfoBasedOnIPRegister(true);
if (_unwindInfoMissing) if (_unwindInfoMissing)
return UNW_STEP_END; return UNW_STEP_END;
if (_info.gp)
setReg(UNW_REG_SP, getReg(UNW_REG_SP) + _info.gp);
} }
return result; return result;

View File

@ -23,22 +23,26 @@
#include "Unwind-EHABI.h" #include "Unwind-EHABI.h"
#include "unwind.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(). /// Called by __cxa_rethrow().
_LIBUNWIND_EXPORT _Unwind_Reason_Code _LIBUNWIND_EXPORT _Unwind_Reason_Code
_Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object) { _Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object) {
#if _LIBUNWIND_ARM_EHABI #if defined(_LIBUNWIND_ARM_EHABI)
_LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%ld", _LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%ld",
(void *)exception_object, (void *)exception_object,
(long)exception_object->unwinder_cache.reserved1); (long)exception_object->unwinder_cache.reserved1);
#else #else
_LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%ld", _LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%" PRIdPTR,
(void *)exception_object, (void *)exception_object,
(long)exception_object->private_1); (intptr_t)exception_object->private_1);
#endif #endif
#if _LIBUNWIND_ARM_EHABI #if defined(_LIBUNWIND_ARM_EHABI)
// _Unwind_RaiseException on EHABI will always set the reserved1 field to 0, // _Unwind_RaiseException on EHABI will always set the reserved1 field to 0,
// which is in the same position as private_1 below. // which is in the same position as private_1 below.
return _Unwind_RaiseException(exception_object); return _Unwind_RaiseException(exception_object);
@ -92,9 +96,9 @@ _LIBUNWIND_EXPORT void *_Unwind_FindEnclosingFunction(void *pc) {
unw_proc_info_t info; unw_proc_info_t info;
unw_getcontext(&uc); unw_getcontext(&uc);
unw_init_local(&cursor, &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) if (unw_get_proc_info(&cursor, &info) == UNW_ESUCCESS)
return (void *)(long) info.start_ip; return (void *)(intptr_t) info.start_ip;
else else
return NULL; return NULL;
} }
@ -111,7 +115,7 @@ _Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) {
_LIBUNWIND_TRACE_API("_Unwind_Backtrace(callback=%p)", _LIBUNWIND_TRACE_API("_Unwind_Backtrace(callback=%p)",
(void *)(uintptr_t)callback); (void *)(uintptr_t)callback);
#if _LIBUNWIND_ARM_EHABI #if defined(_LIBUNWIND_ARM_EHABI)
// Create a mock exception object for force unwinding. // Create a mock exception object for force unwinding.
_Unwind_Exception ex; _Unwind_Exception ex;
memset(&ex, '\0', sizeof(ex)); memset(&ex, '\0', sizeof(ex));
@ -122,7 +126,7 @@ _Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) {
while (true) { while (true) {
_Unwind_Reason_Code result; _Unwind_Reason_Code result;
#if !_LIBUNWIND_ARM_EHABI #if !defined(_LIBUNWIND_ARM_EHABI)
// ask libunwind to get next frame (skip over first frame which is // ask libunwind to get next frame (skip over first frame which is
// _Unwind_Backtrace()) // _Unwind_Backtrace())
if (unw_step(&cursor) <= 0) { if (unw_step(&cursor) <= 0) {
@ -154,7 +158,7 @@ _Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) {
_URC_CONTINUE_UNWIND) { _URC_CONTINUE_UNWIND) {
return _URC_END_OF_STACK; return _URC_END_OF_STACK;
} }
#endif // _LIBUNWIND_ARM_EHABI #endif // defined(_LIBUNWIND_ARM_EHABI)
// debugging // debugging
if (_LIBUNWIND_TRACING_UNWINDING) { 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_name(&cursor, functionName, 512, &offset);
unw_get_proc_info(&cursor, &frame); unw_get_proc_info(&cursor, &frame);
_LIBUNWIND_TRACE_UNWINDING( _LIBUNWIND_TRACE_UNWINDING(
" _backtrace: start_ip=0x%llX, func=%s, lsda=0x%llX, context=%p", " _backtrace: start_ip=0x%" PRIxPTR ", func=%s, lsda=0x%" PRIxPTR ", context=%p",
(long long)frame.start_ip, functionName, (long long)frame.lsda, frame.start_ip, functionName, frame.lsda,
(void *)&cursor); (void *)&cursor);
} }
@ -180,7 +184,7 @@ _Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) {
} }
/// 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, _LIBUNWIND_EXPORT const void *_Unwind_Find_FDE(const void *pc,
struct dwarf_eh_bases *bases) { struct dwarf_eh_bases *bases) {
// This is slow, but works. // 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_proc_info_t info;
unw_getcontext(&uc); unw_getcontext(&uc);
unw_init_local(&cursor, &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); unw_get_proc_info(&cursor, &info);
bases->tbase = (uintptr_t)info.extra; bases->tbase = (uintptr_t)info.extra;
bases->dbase = 0; // dbase not used on Mac OS X bases->dbase = 0; // dbase not used on Mac OS X
bases->func = (uintptr_t)info.start_ip; bases->func = (uintptr_t)info.start_ip;
_LIBUNWIND_TRACE_API("_Unwind_Find_FDE(pc=%p) => %p", pc, _LIBUNWIND_TRACE_API("_Unwind_Find_FDE(pc=%p) => %p", pc,
(void *)(long) info.unwind_info); (void *)(intptr_t) info.unwind_info);
return (void *)(long) info.unwind_info; return (void *)(intptr_t) info.unwind_info;
} }
/// Returns the CFA (call frame area, or stack pointer at start of function) /// 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_cursor_t *cursor = (unw_cursor_t *)context;
unw_word_t result; unw_word_t result;
unw_get_reg(cursor, UNW_REG_SP, &result); unw_get_reg(cursor, UNW_REG_SP, &result);
_LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p) => 0x%" PRIx64, _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p) => 0x%" PRIxPTR,
(void *)context, (uint64_t)result); (void *)context, result);
return (uintptr_t)result; return (uintptr_t)result;
} }
@ -222,7 +226,7 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context,
return _Unwind_GetIP(context); return _Unwind_GetIP(context);
} }
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
#ifdef __FreeBSD__ #ifdef __FreeBSD__
@ -294,7 +298,7 @@ _LIBUNWIND_EXPORT void __deregister_frame(const void *fde) {
// applications working. We also add the not in 10.6 symbol so that nwe // applications working. We also add the not in 10.6 symbol so that nwe
// application won't be able to use them. // 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, _LIBUNWIND_EXPORT void __register_frame_info_bases(const void *fde, void *ob,
void *tb, void *db) { void *tb, void *db) {
(void)fde; (void)fde;
@ -351,8 +355,8 @@ _LIBUNWIND_EXPORT void *__deregister_frame_info_bases(const void *fde) {
// do nothing, this function never worked in Mac OS X // do nothing, this function never worked in Mac OS X
return NULL; 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)

View File

@ -30,7 +30,9 @@
#include "unwind.h" #include "unwind.h"
#include "config.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 static _Unwind_Reason_Code
unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) { unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) {
@ -76,8 +78,8 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
unw_word_t pc; unw_word_t pc;
unw_get_reg(cursor, UNW_REG_IP, &pc); unw_get_reg(cursor, UNW_REG_IP, &pc);
_LIBUNWIND_TRACE_UNWINDING( _LIBUNWIND_TRACE_UNWINDING(
"unwind_phase1(ex_ojb=%p): pc=0x%" PRIx64 ", start_ip=0x%" PRIx64 "unwind_phase1(ex_ojb=%p): pc=0x%" PRIxPTR ", start_ip=0x%" PRIxPTR
", func=%s, lsda=0x%" PRIx64 ", personality=0x%" PRIx64 "", ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR "",
(void *)exception_object, pc, frameInfo.start_ip, functionName, (void *)exception_object, pc, frameInfo.start_ip, functionName,
frameInfo.lsda, frameInfo.handler); frameInfo.lsda, frameInfo.handler);
} }
@ -86,7 +88,7 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
// this frame. // this frame.
if (frameInfo.handler != 0) { if (frameInfo.handler != 0) {
__personality_routine p = __personality_routine p =
(__personality_routine)(long)(frameInfo.handler); (__personality_routine)(uintptr_t)(frameInfo.handler);
_LIBUNWIND_TRACE_UNWINDING( _LIBUNWIND_TRACE_UNWINDING(
"unwind_phase1(ex_ojb=%p): calling personality function %p", "unwind_phase1(ex_ojb=%p): calling personality function %p",
(void *)exception_object, (void *)(uintptr_t)p); (void *)exception_object, (void *)(uintptr_t)p);
@ -170,9 +172,9 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
&offset) != UNW_ESUCCESS) || &offset) != UNW_ESUCCESS) ||
(frameInfo.start_ip + offset > frameInfo.end_ip)) (frameInfo.start_ip + offset > frameInfo.end_ip))
functionName = ".anonymous."; functionName = ".anonymous.";
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIx64 _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIxPTR
", func=%s, sp=0x%" PRIx64 ", lsda=0x%" PRIx64 ", func=%s, sp=0x%" PRIxPTR ", lsda=0x%" PRIxPTR
", personality=0x%" PRIx64, ", personality=0x%" PRIxPTR,
(void *)exception_object, frameInfo.start_ip, (void *)exception_object, frameInfo.start_ip,
functionName, sp, frameInfo.lsda, functionName, sp, frameInfo.lsda,
frameInfo.handler); 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 there is a personality routine, tell it we are unwinding.
if (frameInfo.handler != 0) { if (frameInfo.handler != 0) {
__personality_routine p = __personality_routine p =
(__personality_routine)(long)(frameInfo.handler); (__personality_routine)(uintptr_t)(frameInfo.handler);
_Unwind_Action action = _UA_CLEANUP_PHASE; _Unwind_Action action = _UA_CLEANUP_PHASE;
if (sp == exception_object->private_2) { if (sp == exception_object->private_2) {
// Tell personality this was the frame it marked in phase 1. // Tell personality this was the frame it marked in phase 1.
@ -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_IP, &pc);
unw_get_reg(cursor, UNW_REG_SP, &sp); unw_get_reg(cursor, UNW_REG_SP, &sp);
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering " _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering "
"user code with ip=0x%" PRIx64 "user code with ip=0x%" PRIxPTR
", sp=0x%" PRIx64, ", sp=0x%" PRIxPTR,
(void *)exception_object, pc, sp); (void *)exception_object, pc, sp);
} }
unw_resume(cursor); unw_resume(cursor);
@ -262,8 +264,8 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
(frameInfo.start_ip + offset > frameInfo.end_ip)) (frameInfo.start_ip + offset > frameInfo.end_ip))
functionName = ".anonymous."; functionName = ".anonymous.";
_LIBUNWIND_TRACE_UNWINDING( _LIBUNWIND_TRACE_UNWINDING(
"unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIx64 "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIxPTR
", func=%s, lsda=0x%" PRIx64 ", personality=0x%" PRIx64, ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR,
(void *)exception_object, frameInfo.start_ip, functionName, (void *)exception_object, frameInfo.start_ip, functionName,
frameInfo.lsda, frameInfo.handler); frameInfo.lsda, frameInfo.handler);
} }
@ -287,7 +289,7 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
// If there is a personality routine, tell it we are unwinding. // If there is a personality routine, tell it we are unwinding.
if (frameInfo.handler != 0) { if (frameInfo.handler != 0) {
__personality_routine p = __personality_routine p =
(__personality_routine)(long)(frameInfo.handler); (__personality_routine)(intptr_t)(frameInfo.handler);
_LIBUNWIND_TRACE_UNWINDING( _LIBUNWIND_TRACE_UNWINDING(
"unwind_phase2_forced(ex_ojb=%p): calling personality function %p", "unwind_phase2_forced(ex_ojb=%p): calling personality function %p",
(void *)exception_object, (void *)(uintptr_t)p); (void *)exception_object, (void *)(uintptr_t)p);
@ -449,6 +451,7 @@ _Unwind_GetRegionStart(struct _Unwind_Context *context) {
return result; return result;
} }
#endif // !_LIBUNWIND_SUPPORT_SEH_UNWIND
/// Called by personality handler during phase 2 if a foreign exception /// Called by personality handler during phase 2 if a foreign exception
// is caught. // is caught.
@ -467,17 +470,17 @@ _Unwind_GetGR(struct _Unwind_Context *context, int index) {
unw_cursor_t *cursor = (unw_cursor_t *)context; unw_cursor_t *cursor = (unw_cursor_t *)context;
unw_word_t result; unw_word_t result;
unw_get_reg(cursor, index, &result); unw_get_reg(cursor, index, &result);
_LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%" PRIx64, _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%" PRIxPTR,
(void *)context, index, (uint64_t)result); (void *)context, index, result);
return (uintptr_t)result; return (uintptr_t)result;
} }
/// Called by personality handler during phase 2 to alter register values. /// Called by personality handler during phase 2 to alter register values.
_LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index, _LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index,
uintptr_t value) { uintptr_t value) {
_LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0" PRIx64 _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0" PRIxPTR
")", ")",
(void *)context, index, (uint64_t)value); (void *)context, index, value);
unw_cursor_t *cursor = (unw_cursor_t *)context; unw_cursor_t *cursor = (unw_cursor_t *)context;
unw_set_reg(cursor, index, value); 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_cursor_t *cursor = (unw_cursor_t *)context;
unw_word_t result; unw_word_t result;
unw_get_reg(cursor, UNW_REG_IP, &result); unw_get_reg(cursor, UNW_REG_IP, &result);
_LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIx64, _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIxPTR,
(void *)context, (uint64_t)result); (void *)context, result);
return (uintptr_t)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. /// start executing in the landing pad.
_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context, _LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context,
uintptr_t value) { uintptr_t value) {
_LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0" PRIx64 ")", _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0" PRIxPTR ")",
(void *)context, (uint64_t)value); (void *)context, value);
unw_cursor_t *cursor = (unw_cursor_t *)context; unw_cursor_t *cursor = (unw_cursor_t *)context;
unw_set_reg(cursor, UNW_REG_IP, value); unw_set_reg(cursor, UNW_REG_IP, value);
} }
#endif // !_LIBUNWIND_ARM_EHABI #endif // !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__)

View File

@ -11,11 +11,17 @@
.text .text
#if !defined(__USING_SJLJ_EXCEPTIONS__)
#if defined(__i386__) #if defined(__i386__)
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_x866jumptoEv) DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_x866jumptoEv)
# #
# void libunwind::Registers_x86::jumpto() # 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: # On entry:
# + + # + +
# +-----------------------+ # +-----------------------+
@ -25,6 +31,7 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_x866jumptoEv)
# +-----------------------+ <-- SP # +-----------------------+ <-- SP
# + + # + +
movl 4(%esp), %eax movl 4(%esp), %eax
#endif
# set up eax and ret on new stack location # set up eax and ret on new stack location
movl 28(%eax), %edx # edx holds new stack pointer movl 28(%eax), %edx # edx holds new stack pointer
subl $8,%edx subl $8,%edx
@ -58,7 +65,16 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind16Registers_x86_646jumptoEv)
# #
# void libunwind::Registers_x86_64::jumpto() # 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 # On entry, thread_state pointer is in rdi
#endif
movq 56(%rdi), %rax # rax holds new stack pointer movq 56(%rdi), %rax # rax holds new stack pointer
subq $16, %rax subq $16, %rax
@ -88,11 +104,295 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind16Registers_x86_646jumptoEv)
# skip cs # skip cs
# skip fs # skip fs
# skip gs # 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 movq 56(%rdi), %rsp # cut back rsp to new location
pop %rdi # rdi was saved here earlier pop %rdi # rdi was saved here earlier
ret # rip was saved here 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__) #elif defined(__ppc__)
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv) DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv)
@ -322,9 +622,18 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind15Registers_arm646jumptoEv)
@ @
.p2align 2 .p2align 2
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm20restoreCoreAndJumpToEv) DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm20restoreCoreAndJumpToEv)
#if !defined(__ARM_ARCH_ISA_ARM) #if !defined(__ARM_ARCH_ISA_ARM) && __ARM_ARCH_ISA_THUMB == 1
ldr r2, [r0, #52] @ r8-r11: ldm into r1-r4, then mov to r8-r11
ldr r3, [r0, #60] 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 sp, r2
mov lr, r3 @ restore pc into lr mov lr, r3 @ restore pc into lr
ldm r0, {r0-r7} ldm r0, {r0-r7}
@ -347,7 +656,9 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm20restoreCoreAndJu
@ values pointer is in r0 @ values pointer is in r0
@ @
.p2align 2 .p2align 2
#if defined(__ELF__)
.fpu vfpv3-d16 .fpu vfpv3-d16
#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMDEPy) DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMDEPy)
@ VFP and iwMMX instructions are only available when compiling with the flags @ 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 @ 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 @ values pointer is in r0
@ @
.p2align 2 .p2align 2
#if defined(__ELF__)
.fpu vfpv3-d16 .fpu vfpv3-d16
#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMXEPy) DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMXEPy)
vldmia r0, {d0-d15} @ fldmiax is deprecated in ARMv7+ and now behaves like vldmia vldmia r0, {d0-d15} @ fldmiax is deprecated in ARMv7+ and now behaves like vldmia
JMP(lr) JMP(lr)
@ -378,11 +691,15 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFL
@ values pointer is in r0 @ values pointer is in r0
@ @
.p2align 2 .p2align 2
#if defined(__ELF__)
.fpu vfpv3 .fpu vfpv3
#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreVFPv3EPy) DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreVFPv3EPy)
vldmia r0, {d16-d31} vldmia r0, {d16-d31}
JMP(lr) JMP(lr)
#if defined(__ARM_WMMX)
@ @
@ static void libunwind::Registers_arm::restoreiWMMX(unw_fpreg_t* values) @ 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 @ values pointer is in r0
@ @
.p2align 2 .p2align 2
#if defined(__ELF__)
.arch armv5te
#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreiWMMXEPy) 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, cr0, [r0], #8 @ wldrd wR0, [r0], #8
ldcl p1, cr1, [r0], #8 @ wldrd wR1, [r0], #8 ldcl p1, cr1, [r0], #8 @ wldrd wR1, [r0], #8
ldcl p1, cr2, [r0], #8 @ wldrd wR2, [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, cr13, [r0], #8 @ wldrd wR13, [r0], #8
ldcl p1, cr14, [r0], #8 @ wldrd wR14, [r0], #8 ldcl p1, cr14, [r0], #8 @ wldrd wR14, [r0], #8
ldcl p1, cr15, [r0], #8 @ wldrd wR15, [r0], #8 ldcl p1, cr15, [r0], #8 @ wldrd wR15, [r0], #8
#endif
JMP(lr) JMP(lr)
@ @
@ -418,15 +736,18 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreiWMMXEPy)
@ values pointer is in r0 @ values pointer is in r0
@ @
.p2align 2 .p2align 2
#if defined(__ELF__)
.arch armv5te
#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreiWMMXControlEPj) 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, cr8, [r0], #4 @ wldrw wCGR0, [r0], #4
ldc2 p1, cr9, [r0], #4 @ wldrw wCGR1, [r0], #4 ldc2 p1, cr9, [r0], #4 @ wldrw wCGR1, [r0], #4
ldc2 p1, cr10, [r0], #4 @ wldrw wCGR2, [r0], #4 ldc2 p1, cr10, [r0], #4 @ wldrw wCGR2, [r0], #4
ldc2 p1, cr11, [r0], #4 @ wldrw wCGR3, [r0], #4 ldc2 p1, cr11, [r0], #4 @ wldrw wCGR3, [r0], #4
#endif
JMP(lr) JMP(lr)
#endif
#elif defined(__or1k__) #elif defined(__or1k__)
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv) DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv)
@ -437,7 +758,7 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv)
# thread_state pointer is in r3 # thread_state pointer is in r3
# #
# restore integral registerrs # restore integral registers
l.lwz r0, 0(r3) l.lwz r0, 0(r3)
l.lwz r1, 4(r3) l.lwz r1, 4(r3)
l.lwz r2, 8(r3) l.lwz r2, 8(r3)
@ -447,7 +768,7 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv)
l.lwz r6, 24(r3) l.lwz r6, 24(r3)
l.lwz r7, 28(r3) l.lwz r7, 28(r3)
l.lwz r8, 32(r3) l.lwz r8, 32(r3)
l.lwz r9, 36(r3) # skip r9
l.lwz r10, 40(r3) l.lwz r10, 40(r3)
l.lwz r11, 44(r3) l.lwz r11, 44(r3)
l.lwz r12, 48(r3) l.lwz r12, 48(r3)
@ -474,6 +795,8 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv)
# at last, restore r3 # at last, restore r3
l.lwz r3, 12(r3) l.lwz r3, 12(r3)
# load new pc into ra
l.lwz r9, 128(r3)
# jump to pc # jump to pc
l.jr r9 l.jr r9
l.nop l.nop
@ -573,7 +896,7 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind18Registers_mips_o326jumptoEv)
.set noreorder .set noreorder
.set nomacro .set nomacro
#ifdef __mips_hard_float #ifdef __mips_hard_float
#if __mips_fpr == 32 #if __mips_fpr != 64
ldc1 $f0, (4 * 36 + 8 * 0)($4) ldc1 $f0, (4 * 36 + 8 * 0)($4)
ldc1 $f2, (4 * 36 + 8 * 2)($4) ldc1 $f2, (4 * 36 + 8 * 2)($4)
ldc1 $f4, (4 * 36 + 8 * 4)($4) ldc1 $f4, (4 * 36 + 8 * 4)($4)
@ -758,7 +1081,31 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind21Registers_mips_newabi6jumptoEv)
ld $4, (8 * 4)($4) ld $4, (8 * 4)($4)
.set pop .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
#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
NO_EXEC_STACK_DIRECTIVE NO_EXEC_STACK_DIRECTIVE

View File

@ -11,6 +11,8 @@
.text .text
#if !defined(__USING_SJLJ_EXCEPTIONS__)
#if defined(__i386__) #if defined(__i386__)
# #
@ -61,29 +63,56 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
# thread_state pointer is in rdi # thread_state pointer is in rdi
# #
DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
movq %rax, (%rdi) #if defined(_WIN64)
movq %rbx, 8(%rdi) #define PTR %rcx
movq %rcx, 16(%rdi) #define TMP %rdx
movq %rdx, 24(%rdi) #else
movq %rdi, 32(%rdi) #define PTR %rdi
movq %rsi, 40(%rdi) #define TMP %rsi
movq %rbp, 48(%rdi) #endif
movq %rsp, 56(%rdi)
addq $8, 56(%rdi) movq %rax, (PTR)
movq %r8, 64(%rdi) movq %rbx, 8(PTR)
movq %r9, 72(%rdi) movq %rcx, 16(PTR)
movq %r10, 80(%rdi) movq %rdx, 24(PTR)
movq %r11, 88(%rdi) movq %rdi, 32(PTR)
movq %r12, 96(%rdi) movq %rsi, 40(PTR)
movq %r13,104(%rdi) movq %rbp, 48(PTR)
movq %r14,112(%rdi) movq %rsp, 56(PTR)
movq %r15,120(%rdi) addq $8, 56(PTR)
movq (%rsp),%rsi movq %r8, 64(PTR)
movq %rsi,128(%rdi) # store return address as rip 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 rflags
# skip cs # skip cs
# skip fs # skip fs
# skip gs # 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 xorl %eax, %eax # return UNW_ESUCCESS
ret ret
@ -139,7 +168,7 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
mflo $8 mflo $8
sw $8, (4 * 34)($4) sw $8, (4 * 34)($4)
#ifdef __mips_hard_float #ifdef __mips_hard_float
#if __mips_fpr == 32 #if __mips_fpr != 64
sdc1 $f0, (4 * 36 + 8 * 0)($4) sdc1 $f0, (4 * 36 + 8 * 0)($4)
sdc1 $f2, (4 * 36 + 8 * 2)($4) sdc1 $f2, (4 * 36 + 8 * 2)($4)
sdc1 $f4, (4 * 36 + 8 * 4)($4) sdc1 $f4, (4 * 36 + 8 * 4)($4)
@ -295,6 +324,237 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
teq $0, $0 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__) #elif defined(__ppc__)
; ;
@ -508,13 +768,24 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
@ @
.p2align 2 .p2align 2
DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
#if !defined(__ARM_ARCH_ISA_ARM) #if !defined(__ARM_ARCH_ISA_ARM) && __ARM_ARCH_ISA_THUMB == 1
stm r0, {r0-r7} stm r0!, {r0-r7}
mov r1, r8
mov r2, r9
mov r3, r10
stm r0!, {r1-r3}
mov r1, r11
mov r2, sp mov r2, sp
mov r3, lr mov r3, lr
str r2, [r0, #52] str r1, [r0, #0] @ r11
str r3, [r0, #56] @ r12 does not need storing, it it the intra-procedure-call scratch register
str r3, [r0, #60] @ store return address as pc 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 #else
@ 32bit thumb-2 restrictions for stm: @ 32bit thumb-2 restrictions for stm:
@ . the sp (r13) cannot be in the list @ . the sp (r13) cannot be in the list
@ -523,13 +794,6 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
str sp, [r0, #52] str sp, [r0, #52]
str lr, [r0, #56] str lr, [r0, #56]
str lr, [r0, #60] @ store return address as pc 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 mov r0, #0 @ return UNW_ESUCCESS
#endif #endif
JMP(lr) JMP(lr)
@ -541,7 +805,9 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
@ values pointer is in r0 @ values pointer is in r0
@ @
.p2align 2 .p2align 2
#if defined(__ELF__)
.fpu vfpv3-d16 .fpu vfpv3-d16
#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMDEPy) DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMDEPy)
vstmia r0, {d0-d15} vstmia r0, {d0-d15}
JMP(lr) JMP(lr)
@ -553,7 +819,9 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMD
@ values pointer is in r0 @ values pointer is in r0
@ @
.p2align 2 .p2align 2
#if defined(__ELF__)
.fpu vfpv3-d16 .fpu vfpv3-d16
#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMXEPy) DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMXEPy)
vstmia r0, {d0-d15} @ fstmiax is deprecated in ARMv7+ and now behaves like vstmia vstmia r0, {d0-d15} @ fstmiax is deprecated in ARMv7+ and now behaves like vstmia
JMP(lr) JMP(lr)
@ -565,7 +833,9 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMX
@ values pointer is in r0 @ values pointer is in r0
@ @
.p2align 2 .p2align 2
#if defined(__ELF__)
.fpu vfpv3 .fpu vfpv3
#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveVFPv3EPy) DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveVFPv3EPy)
@ VFP and iwMMX instructions are only available when compiling with the flags @ 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 @ that enable them. We do not want to do that in the library (because we do not
@ -577,6 +847,8 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveVFPv3EPy)
vstmia r0, {d16-d31} vstmia r0, {d16-d31}
JMP(lr) JMP(lr)
#if defined(_LIBUNWIND_ARM_WMMX)
@ @
@ static void libunwind::Registers_arm::saveiWMMX(unw_fpreg_t* values) @ static void libunwind::Registers_arm::saveiWMMX(unw_fpreg_t* values)
@ @
@ -584,8 +856,10 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveVFPv3EPy)
@ values pointer is in r0 @ values pointer is in r0
@ @
.p2align 2 .p2align 2
#if defined(__ELF__)
.arch armv5te
#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveiWMMXEPy) 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, cr0, [r0], #8 @ wstrd wR0, [r0], #8
stcl p1, cr1, [r0], #8 @ wstrd wR1, [r0], #8 stcl p1, cr1, [r0], #8 @ wstrd wR1, [r0], #8
stcl p1, cr2, [r0], #8 @ wstrd wR2, [r0], #8 stcl p1, cr2, [r0], #8 @ wstrd wR2, [r0], #8
@ -602,7 +876,6 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveiWMMXEPy)
stcl p1, cr13, [r0], #8 @ wstrd wR13, [r0], #8 stcl p1, cr13, [r0], #8 @ wstrd wR13, [r0], #8
stcl p1, cr14, [r0], #8 @ wstrd wR14, [r0], #8 stcl p1, cr14, [r0], #8 @ wstrd wR14, [r0], #8
stcl p1, cr15, [r0], #8 @ wstrd wR15, [r0], #8 stcl p1, cr15, [r0], #8 @ wstrd wR15, [r0], #8
#endif
JMP(lr) JMP(lr)
@ @
@ -612,15 +885,18 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveiWMMXEPy)
@ values pointer is in r0 @ values pointer is in r0
@ @
.p2align 2 .p2align 2
#if defined(__ELF__)
.arch armv5te
#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveiWMMXControlEPj) 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, cr8, [r0], #4 @ wstrw wCGR0, [r0], #4
stc2 p1, cr9, [r0], #4 @ wstrw wCGR1, [r0], #4 stc2 p1, cr9, [r0], #4 @ wstrw wCGR1, [r0], #4
stc2 p1, cr10, [r0], #4 @ wstrw wCGR2, [r0], #4 stc2 p1, cr10, [r0], #4 @ wstrw wCGR2, [r0], #4
stc2 p1, cr11, [r0], #4 @ wstrw wCGR3, [r0], #4 stc2 p1, cr11, [r0], #4 @ wstrw wCGR3, [r0], #4
#endif
JMP(lr) JMP(lr)
#endif
#elif defined(__or1k__) #elif defined(__or1k__)
# #
@ -662,6 +938,10 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
l.sw 116(r3), r29 l.sw 116(r3), r29
l.sw 120(r3), r30 l.sw 120(r3), r30
l.sw 124(r3), r31 l.sw 124(r3), r31
# store ra to pc
l.sw 128(r3), r9
# zero epcr
l.sw 132(r3), r0
#elif defined(__riscv) #elif defined(__riscv)
@ -742,7 +1022,37 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
li a0, 0 // return UNW_ESUCCESS li a0, 0 // return UNW_ESUCCESS
ret // jump to ra ret // jump to ra
#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
#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
NO_EXEC_STACK_DIRECTIVE NO_EXEC_STACK_DIRECTIVE

View File

@ -9,8 +9,8 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "config.h" #include "config.h"
#include "AddressSpace.hpp"
#include "DwarfParser.hpp" #include "DwarfParser.hpp"
#include "unwind_ext.h"
// private keymgr stuff // private keymgr stuff
@ -76,7 +76,7 @@ struct libgcc_object_info {
#endif #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 // 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)
NEVER_HERE(__deregister_frame_info_bases) 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 // symbols in libSystem.dylib in iOS 5.0 and later, but are in libgcc_s.dylib in
// earlier versions // 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_Resume_or_Rethrow)
NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Unregister) NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Unregister)
#endif // _LIBUNWIND_BUILD_SJLJ_APIS #endif // defined(_LIBUNWIND_BUILD_SJLJ_APIS)
namespace libunwind { namespace libunwind {
@ -182,24 +182,3 @@ bool checkKeyMgrRegisteredFDEs(uintptr_t pc, void *&fde) {
} }
#if !defined(FOR_DYLD) && _LIBUNWIND_BUILD_SJLJ_APIS
#include <System/pthread_machdep.h>
// 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

View File

@ -16,7 +16,20 @@
#ifndef UNWIND_ASSEMBLY_H #ifndef UNWIND_ASSEMBLY_H
#define 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 @ #define SEPARATOR @
#elif defined(__arm64__) #elif defined(__arm64__)
#define SEPARATOR %% #define SEPARATOR %%
@ -24,12 +37,6 @@
#define SEPARATOR ; #define SEPARATOR ;
#endif #endif
#if defined(__APPLE__)
#define HIDDEN_DIRECTIVE .private_extern
#else
#define HIDDEN_DIRECTIVE .hidden
#endif
#define GLUE2(a, b) a ## b #define GLUE2(a, b) a ## b
#define GLUE(a, b) GLUE2(a, b) #define GLUE(a, b) GLUE2(a, b)
#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name) #define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
@ -37,6 +44,8 @@
#if defined(__APPLE__) #if defined(__APPLE__)
#define SYMBOL_IS_FUNC(name) #define SYMBOL_IS_FUNC(name)
#define EXPORT_SYMBOL(name)
#define HIDDEN_SYMBOL(name) .private_extern name
#define NO_EXEC_STACK_DIRECTIVE #define NO_EXEC_STACK_DIRECTIVE
#elif defined(__ELF__) #elif defined(__ELF__)
@ -46,33 +55,53 @@
#else #else
#define SYMBOL_IS_FUNC(name) .type name,@function #define SYMBOL_IS_FUNC(name) .type name,@function
#endif #endif
#define EXPORT_SYMBOL(name)
#define HIDDEN_SYMBOL(name) .hidden name
#if defined(__GNU__) || defined(__ANDROID__) || defined(__FreeBSD__) #if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \
defined(__linux__)
#define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits #define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits
#else #else
#define NO_EXEC_STACK_DIRECTIVE #define NO_EXEC_STACK_DIRECTIVE
#endif #endif
#else #elif defined(_WIN32)
#define SYMBOL_IS_FUNC(name) \ #define SYMBOL_IS_FUNC(name) \
.def name SEPARATOR \ .def name SEPARATOR \
.scl 2 SEPARATOR \ .scl 2 SEPARATOR \
.type 32 SEPARATOR \ .type 32 SEPARATOR \
.endef .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 #define NO_EXEC_STACK_DIRECTIVE
#elif defined(__sparc__)
#else
#error Unsupported target
#endif #endif
#define DEFINE_LIBUNWIND_FUNCTION(name) \ #define DEFINE_LIBUNWIND_FUNCTION(name) \
.globl SYMBOL_NAME(name) SEPARATOR \ .globl SYMBOL_NAME(name) SEPARATOR \
EXPORT_SYMBOL(name) SEPARATOR \
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
SYMBOL_NAME(name): SYMBOL_NAME(name):
#define DEFINE_LIBUNWIND_PRIVATE_FUNCTION(name) \ #define DEFINE_LIBUNWIND_PRIVATE_FUNCTION(name) \
.globl SYMBOL_NAME(name) SEPARATOR \ .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_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
SYMBOL_NAME(name): SYMBOL_NAME(name):

View File

@ -16,6 +16,7 @@
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
// Define static_assert() unless already defined by compiler. // Define static_assert() unless already defined by compiler.
@ -31,52 +32,66 @@
// Platform specific configuration defines. // Platform specific configuration defines.
#ifdef __APPLE__ #ifdef __APPLE__
#if defined(FOR_DYLD) #if defined(FOR_DYLD)
#define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1 #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND
#define _LIBUNWIND_SUPPORT_DWARF_UNWIND 0
#define _LIBUNWIND_SUPPORT_DWARF_INDEX 0
#else #else
#define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1 #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND
#define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 #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 #endif
#else #else
#if defined(__ARM_DWARF_EH__) || !defined(__arm__) #if defined(__ARM_DWARF_EH__) || !defined(__arm__)
#define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 0
#define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
#define _LIBUNWIND_SUPPORT_DWARF_INDEX 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
#endif #endif
// FIXME: these macros are not correct for COFF targets #if defined(_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS)
#define _LIBUNWIND_EXPORT __attribute__((visibility("default"))) #define _LIBUNWIND_EXPORT
#define _LIBUNWIND_HIDDEN __attribute__((visibility("hidden"))) #define _LIBUNWIND_HIDDEN
#if (defined(__APPLE__) && defined(__arm__)) || defined(__USING_SJLJ_EXCEPTIONS__)
#define _LIBUNWIND_BUILD_SJLJ_APIS 1
#else #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 #endif
#if defined(__i386__) || defined(__x86_64__) #if (defined(__APPLE__) && defined(__arm__)) || defined(__USING_SJLJ_EXCEPTIONS__)
#define _LIBUNWIND_SUPPORT_FRAME_APIS 1 #define _LIBUNWIND_BUILD_SJLJ_APIS
#else #endif
#define _LIBUNWIND_SUPPORT_FRAME_APIS 0
#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__ppc64__) || defined(__powerpc64__)
#define _LIBUNWIND_SUPPORT_FRAME_APIS
#endif #endif
#if defined(__i386__) || defined(__x86_64__) || \ #if defined(__i386__) || defined(__x86_64__) || \
defined(__ppc__) || defined(__ppc64__) || defined(__powerpc64__) || \
(!defined(__APPLE__) && defined(__arm__)) || \ (!defined(__APPLE__) && defined(__arm__)) || \
(defined(__arm64__) || defined(__aarch64__)) || \ (defined(__arm64__) || defined(__aarch64__)) || \
(defined(__mips__)) || \ defined(__mips__) || \
defined(__riscv) defined(__riscv)
#define _LIBUNWIND_BUILD_ZERO_COST_APIS 1 #if !defined(_LIBUNWIND_BUILD_SJLJ_APIS)
#else #define _LIBUNWIND_BUILD_ZERO_COST_APIS
#define _LIBUNWIND_BUILD_ZERO_COST_APIS 0 #endif
#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) \ #define _LIBUNWIND_ABORT(msg) \
do { \ do { \
fprintf(stderr, "libunwind: %s %s:%d - %s\n", __func__, __FILE__, \ fprintf(stderr, "libunwind: %s %s:%d - %s\n", __func__, __FILE__, \
@ -84,40 +99,65 @@
fflush(stderr); \ fflush(stderr); \
abort(); \ abort(); \
} while (0) } while (0)
#define _LIBUNWIND_LOG(msg, ...) fprintf(stderr, "libunwind: " msg "\n", __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 // Macros that define away in non-Debug builds
#ifdef NDEBUG #ifdef NDEBUG
#define _LIBUNWIND_DEBUG_LOG(msg, ...) #define _LIBUNWIND_DEBUG_LOG(msg, ...)
#define _LIBUNWIND_TRACE_API(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_TRACE_UNWINDING(msg, ...)
#define _LIBUNWIND_LOG_NON_ZERO(x) x #define _LIBUNWIND_TRACE_DWARF(...)
#else #else
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
extern bool logAPIs(); extern bool logAPIs();
extern bool logUnwinding(); extern bool logUnwinding();
extern bool logDWARF();
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#define _LIBUNWIND_DEBUG_LOG(msg, ...) _LIBUNWIND_LOG(msg, __VA_ARGS__) #define _LIBUNWIND_DEBUG_LOG(msg, ...) _LIBUNWIND_LOG(msg, __VA_ARGS__)
#define _LIBUNWIND_LOG_NON_ZERO(x) \ #define _LIBUNWIND_TRACE_API(msg, ...) \
do { \ do { \
int _err = x; \ if (logAPIs()) \
if ( _err != 0 ) \ _LIBUNWIND_LOG(msg, __VA_ARGS__); \
_LIBUNWIND_LOG("" #x "=%d in %s", _err, __FUNCTION__); \ } while (0)
} 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_TRACING_UNWINDING logUnwinding() #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 #endif
#ifdef __cplusplus #ifdef __cplusplus
@ -126,7 +166,7 @@
#if defined(_LIBUNWIND_IS_NATIVE_ONLY) #if defined(_LIBUNWIND_IS_NATIVE_ONLY)
# define COMP_OP == # define COMP_OP ==
#else #else
# define COMP_OP < # define COMP_OP <=
#endif #endif
template <typename _Type, typename _Mem> template <typename _Type, typename _Mem>
struct check_fit { struct check_fit {

View File

@ -49,7 +49,10 @@ enum {
// GNU extensions // GNU extensions
DW_CFA_GNU_window_save = 0x2D, DW_CFA_GNU_window_save = 0x2D,
DW_CFA_GNU_args_size = 0x2E, 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
}; };

View File

@ -24,6 +24,8 @@
#include <stdlib.h> #include <stdlib.h>
#if !defined(__USING_SJLJ_EXCEPTIONS__)
#include "AddressSpace.hpp"
#include "UnwindCursor.hpp" #include "UnwindCursor.hpp"
using namespace libunwind; using namespace libunwind;
@ -49,11 +51,13 @@ _LIBUNWIND_EXPORT int unw_init_local(unw_cursor_t *cursor,
# define REGISTER_KIND Registers_x86 # define REGISTER_KIND Registers_x86
#elif defined(__x86_64__) #elif defined(__x86_64__)
# define REGISTER_KIND Registers_x86_64 # define REGISTER_KIND Registers_x86_64
#elif defined(__powerpc64__)
# define REGISTER_KIND Registers_ppc64
#elif defined(__ppc__) #elif defined(__ppc__)
# define REGISTER_KIND Registers_ppc # define REGISTER_KIND Registers_ppc
#elif defined(__aarch64__) #elif defined(__aarch64__)
# define REGISTER_KIND Registers_arm64 # define REGISTER_KIND Registers_arm64
#elif _LIBUNWIND_ARM_EHABI #elif defined(__arm__)
# define REGISTER_KIND Registers_arm # define REGISTER_KIND Registers_arm
#elif defined(__or1k__) #elif defined(__or1k__)
# define REGISTER_KIND Registers_or1k # define REGISTER_KIND Registers_or1k
@ -65,6 +69,8 @@ _LIBUNWIND_EXPORT int unw_init_local(unw_cursor_t *cursor,
# define REGISTER_KIND Registers_mips_newabi # define REGISTER_KIND Registers_mips_newabi
#elif defined(__mips__) #elif defined(__mips__)
# warning The MIPS architecture is not supported with this ABI and environment! # warning The MIPS architecture is not supported with this ABI and environment!
#elif defined(__sparc__)
# define REGISTER_KIND Registers_sparc
#else #else
# error Architecture not supported # error Architecture not supported
#endif #endif
@ -91,18 +97,18 @@ _LIBUNWIND_EXPORT int unw_init_remote_thread(unw_cursor_t *cursor,
switch (as->cpuType) { switch (as->cpuType) {
case CPU_TYPE_I386: case CPU_TYPE_I386:
new ((void *)cursor) new ((void *)cursor)
UnwindCursor<OtherAddressSpace<Pointer32<LittleEndian> >, UnwindCursor<RemoteAddressSpace<Pointer32<LittleEndian>>,
Registers_x86>(((unw_addr_space_i386 *)as)->oas, arg); Registers_x86>(((unw_addr_space_i386 *)as)->oas, arg);
break; break;
case CPU_TYPE_X86_64: case CPU_TYPE_X86_64:
new ((void *)cursor) UnwindCursor< new ((void *)cursor)
OtherAddressSpace<Pointer64<LittleEndian> >, Registers_x86_64>( UnwindCursor<RemoteAddressSpace<Pointer64<LittleEndian>>,
((unw_addr_space_x86_64 *)as)->oas, arg); Registers_x86_64>(((unw_addr_space_x86_64 *)as)->oas, arg);
break; break;
case CPU_TYPE_POWERPC: case CPU_TYPE_POWERPC:
new ((void *)cursor) new ((void *)cursor)
UnwindCursor<OtherAddressSpace<Pointer32<BigEndian> >, Registers_ppc>( UnwindCursor<RemoteAddressSpace<Pointer32<BigEndian>>,
((unw_addr_space_ppc *)as)->oas, arg); Registers_ppc>(((unw_addr_space_ppc *)as)->oas, arg);
break; break;
default: default:
return UNW_EUNSPEC; return UNW_EUNSPEC;
@ -178,16 +184,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. /// 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, _LIBUNWIND_EXPORT int unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
unw_word_t value) { unw_word_t value) {
_LIBUNWIND_TRACE_API("unw_set_reg(cursor=%p, regNum=%d, value=0x%llX)", _LIBUNWIND_TRACE_API("unw_set_reg(cursor=%p, regNum=%d, value=0x%" PRIxPTR ")",
static_cast<void *>(cursor), regNum, (long long)value); static_cast<void *>(cursor), regNum, value);
typedef LocalAddressSpace::pint_t pint_t; typedef LocalAddressSpace::pint_t pint_t;
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
if (co->validReg(regNum)) { if (co->validReg(regNum)) {
co->setReg(regNum, (pint_t)value); co->setReg(regNum, (pint_t)value);
// specical case altering IP to re-find info (being called by personality // specical case altering IP to re-find info (being called by personality
// function) // 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); 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_ESUCCESS;
} }
return UNW_EBADREG; return UNW_EBADREG;
@ -212,7 +230,7 @@ _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. /// 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, _LIBUNWIND_EXPORT int unw_set_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum,
unw_fpreg_t value) { unw_fpreg_t value) {
#if _LIBUNWIND_ARM_EHABI #if defined(_LIBUNWIND_ARM_EHABI)
_LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%llX)", _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%llX)",
static_cast<void *>(cursor), regNum, value); static_cast<void *>(cursor), regNum, value);
#else #else
@ -311,8 +329,8 @@ _LIBUNWIND_EXPORT void unw_save_vfp_as_X(unw_cursor_t *cursor) {
#endif #endif
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
/// SPI: walks cached dwarf entries /// SPI: walks cached DWARF entries
_LIBUNWIND_EXPORT void unw_iterate_dwarf_unwind_cache(void (*func)( _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)) { 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)", _LIBUNWIND_TRACE_API("unw_iterate_dwarf_unwind_cache(func=%p)",
@ -345,7 +363,8 @@ void _unw_remove_dynamic_fde(unw_word_t fde) {
// fde is own mh_group // fde is own mh_group
DwarfFDECache<LocalAddressSpace>::removeAllIn((LocalAddressSpace::pint_t)fde); DwarfFDECache<LocalAddressSpace>::removeAllIn((LocalAddressSpace::pint_t)fde);
} }
#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND #endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
#endif // !defined(__USING_SJLJ_EXCEPTIONS__)
@ -377,5 +396,17 @@ bool logUnwinding() {
return log; 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 #endif // NDEBUG

View File

@ -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_add_dynamic_fde(unw_word_t fde);
extern void _unw_remove_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 const uint32_t* decode_eht_entry(const uint32_t*, size_t*, size_t*);
extern _Unwind_Reason_Code _Unwind_VRS_Interpret(_Unwind_Context *context, extern _Unwind_Reason_Code _Unwind_VRS_Interpret(_Unwind_Context *context,
const uint32_t *data, const uint32_t *data,

View File

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

View File

@ -57,7 +57,7 @@ growfs_start ()
;; ;;
zfs) zfs)
pool=${FSDEV%%/*} 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" echo "Don't know how to grow root filesystem type: $FSTYPE"

View File

@ -32,7 +32,7 @@ doceng [label="Documentation Engineering Team\ndoceng@FreeBSD.org\nbcr, gabor, g
portscommitters [label="Ports Committers\nports-committers@FreeBSD.org"] portscommitters [label="Ports Committers\nports-committers@FreeBSD.org"]
portmgr [label="Port Management Team\nportmgr@FreeBSD.org\nadamw, antoine, bapt, bdrewery\nfeld, mat, rene, swills"] 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"] 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"] 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"] 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"] secteamsecretary [label="Security Team Secretary\nsecteam-secretary@FreeBSD.org\nremko"]
@ -41,15 +41,14 @@ srccommitters [label="Src Committers\nsrc-committers@FreeBSD.org"]
# Admin teams go here alphabetically sorted # Admin teams go here alphabetically sorted
accounts [label="Accounts Team\naccounts@FreeBSD.org\nmarkm, simon, kensmith,\ndhw"] accounts [label="Accounts Team\naccounts@FreeBSD.org\nclusteradm"]
backups [label="Backup Administrators\nbackups@FreeBSD.org\nsimon, kensmith,\ndhw"] backups [label="Backup Administrators\nbackups@FreeBSD.org\nclusteradm"]
bugmeister [label="Bugmeister Team\nbugmeister@FreeBSD.org\neadler, gavin, gonzo"] 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"] 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"] dnsadm [label="DNS Administrators\ndnsadm@FreeBSD.org\nclusteradm"]
mirroradmin [label="FTP/WWW Mirror Site Coordinators\nmirror-admin@FreeBSD.org\nkuriyama, kensmith"] 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"] 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"] 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"] webmaster [label="Webmaster Team\nwebmaster@FreeBSD.org\ngjb, wblock, blackend,\ngabor, hrs, wosch"]
# Misc hats go here alphabetically sorted # Misc hats go here alphabetically sorted
@ -69,7 +68,6 @@ _admin -> clusteradm
_admin -> dnsadm _admin -> dnsadm
_admin -> mirroradmin _admin -> mirroradmin
_admin -> perforceadmin _admin -> perforceadmin
_admin -> refadm
_admin -> postmaster _admin -> postmaster
_admin -> webmaster _admin -> webmaster

View File

@ -424,6 +424,7 @@ spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
} }
mtx_lock(&sc->mtx); mtx_lock(&sc->mtx);
device_busy(sc->dev);
if (sc->debug >= 1) { if (sc->debug >= 1) {
device_printf(sc->dev, 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); spi_set_chipsel(sc, cs, false);
WR4(sc, ECSPI_CTLREG, 0); WR4(sc, ECSPI_CTLREG, 0);
device_unbusy(sc->dev);
mtx_unlock(&sc->mtx); mtx_unlock(&sc->mtx);
return (err); return (err);
@ -468,11 +470,11 @@ static int
spi_detach(device_t dev) spi_detach(device_t dev)
{ {
struct spi_softc *sc = device_get_softc(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) if (sc->spibus != NULL)
device_delete_child(dev, sc->spibus); device_delete_child(dev, sc->spibus);
@ -488,7 +490,6 @@ spi_detach(device_t dev)
if (sc->memres != NULL) if (sc->memres != NULL)
bus_release_resource(sc->dev, SYS_RES_MEMORY, 0, sc->memres); bus_release_resource(sc->dev, SYS_RES_MEMORY, 0, sc->memres);
mtx_unlock(&sc->mtx);
mtx_destroy(&sc->mtx); mtx_destroy(&sc->mtx);
return (0); return (0);

View File

@ -865,11 +865,12 @@ static struct da_quirk_entry da_quirk_table[] =
}, },
{ {
/* /*
* 16GB SLC CHIPFANCIER * SLC CHIPFANCIER USB drives
* PR: usb/234503 * PR: usb/234503 (RC10 right, RC16 wrong)
* 16GB, 32GB and 128GB confirmed to have same issue
*/ */
{T_DIRECT, SIP_MEDIA_REMOVABLE, "16G SLC", "CHIPFANCIER", {T_DIRECT, SIP_MEDIA_REMOVABLE, "*SLC", "CHIPFANCIER",
"1.00"}, /*quirks*/ DA_Q_NO_RC16 "*"}, /*quirks*/ DA_Q_NO_RC16
}, },
/* ATA/SATA devices over SAS/USB/... */ /* ATA/SATA devices over SAS/USB/... */
{ {

View File

@ -692,7 +692,7 @@ vdev_queue_aggregate(vdev_queue_t *vq, zio_t *zio)
limit = zfs_vdev_aggregation_limit; limit = zfs_vdev_aggregation_limit;
limit = MAX(MIN(limit, maxblocksize), 0); 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); return (NULL);
first = last = zio; first = last = zio;

View File

@ -755,10 +755,6 @@ zfsctl_common_pathconf(ap)
*ap->a_retval = (int)SPA_MINBLOCKSIZE; *ap->a_retval = (int)SPA_MINBLOCKSIZE;
return (0); return (0);
case _PC_ACL_EXTENDED:
*ap->a_retval = 0;
return (0);
case _PC_ACL_NFS4: case _PC_ACL_NFS4:
*ap->a_retval = 1; *ap->a_retval = 1;
return (0); return (0);

View File

@ -2791,6 +2791,7 @@ isp_getpdb(ispsoftc_t *isp, int chan, uint16_t id, isp_pdb_t *pdb)
if (IS_24XX(isp)) { if (IS_24XX(isp)) {
isp_get_pdb_24xx(isp, isp->isp_iocb, &un.bill); isp_get_pdb_24xx(isp, isp->isp_iocb, &un.bill);
pdb->handle = un.bill.pdb_handle; pdb->handle = un.bill.pdb_handle;
pdb->prli_word0 = un.bill.pdb_prli_svc0;
pdb->prli_word3 = un.bill.pdb_prli_svc3; pdb->prli_word3 = un.bill.pdb_prli_svc3;
pdb->portid = BITS2WORD_24XX(un.bill.pdb_portid_bits); pdb->portid = BITS2WORD_24XX(un.bill.pdb_portid_bits);
ISP_MEMCPY(pdb->portname, un.bill.pdb_portname, 8); 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 { } else {
isp_get_pdb_21xx(isp, isp->isp_iocb, &un.fred); isp_get_pdb_21xx(isp, isp->isp_iocb, &un.fred);
pdb->handle = un.fred.pdb_loopid; pdb->handle = un.fred.pdb_loopid;
pdb->prli_word0 = un.fred.pdb_prli_svc0;
pdb->prli_word3 = un.fred.pdb_prli_svc3; pdb->prli_word3 = un.fred.pdb_prli_svc3;
pdb->portid = BITS2WORD(un.fred.pdb_portid_bits); pdb->portid = BITS2WORD(un.fred.pdb_portid_bits);
ISP_MEMCPY(pdb->portname, un.fred.pdb_portname, 8); 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; lp->state = FC_PORTDB_STATE_VALID;
isp_async(isp, ISPASYNC_DEV_CHANGED, chan, lp); isp_async(isp, ISPASYNC_DEV_CHANGED, chan, lp);
lp->portid = lp->new_portid; lp->portid = lp->new_portid;
lp->prli_word0 = lp->new_prli_word0;
lp->prli_word3 = lp->new_prli_word3; lp->prli_word3 = lp->new_prli_word3;
break; break;
case FC_PORTDB_STATE_VALID: 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. */ /* Old device, nothing new. */
if (lp->portid == pdb->portid && if (lp->portid == pdb->portid &&
lp->handle == pdb->handle && 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) if (lp->state != FC_PORTDB_STATE_NEW)
lp->state = FC_PORTDB_STATE_VALID; lp->state = FC_PORTDB_STATE_VALID;
isp_prt(isp, ISP_LOG_SANCFG, 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->state = FC_PORTDB_STATE_CHANGED;
lp->handle = pdb->handle; lp->handle = pdb->handle;
lp->new_portid = pdb->portid; lp->new_portid = pdb->portid;
lp->new_prli_word0 = pdb->prli_word0;
lp->new_prli_word3 = pdb->prli_word3; lp->new_prli_word3 = pdb->prli_word3;
isp_prt(isp, ISP_LOG_SANCFG, isp_prt(isp, ISP_LOG_SANCFG,
"Chan %d Port 0x%06x@0x%04x is changed", "Chan %d Port 0x%06x@0x%04x is changed",

View File

@ -3742,6 +3742,10 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
break; break;
case ISPASYNC_DEV_CHANGED: case ISPASYNC_DEV_CHANGED:
case ISPASYNC_DEV_STAYED: case ISPASYNC_DEV_STAYED:
{
int crn_reset_done;
crn_reset_done = 0;
va_start(ap, cmd); va_start(ap, cmd);
bus = va_arg(ap, int); bus = va_arg(ap, int);
lp = va_arg(ap, fcportdb_t *); 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->new_prli_word3 & PRLI_WD3_TARGET_FUNCTION))) {
lp->is_target = !lp->is_target; lp->is_target = !lp->is_target;
if (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); isp_fcp_reset_crn(isp, bus, tgt, /*tgt_set*/ 1);
crn_reset_done = 1;
}
isp_make_here(isp, lp, bus, tgt); isp_make_here(isp, lp, bus, tgt);
} else { } else {
isp_make_gone(isp, lp, bus, tgt); 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); isp_fcp_reset_crn(isp, bus, tgt, /*tgt_set*/ 1);
crn_reset_done = 1;
}
} }
} }
if (lp->is_initiator != if (lp->is_initiator !=
@ -3780,7 +3788,13 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
adc->arrived = lp->is_initiator; adc->arrived = lp->is_initiator;
xpt_async(AC_CONTRACT, fc->path, &ac); 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; break;
}
case ISPASYNC_DEV_GONE: case ISPASYNC_DEV_GONE:
va_start(ap, cmd); va_start(ap, cmd);
bus = va_arg(ap, int); bus = va_arg(ap, int);

View File

@ -283,6 +283,14 @@ typedef struct {
#define ADISC 0x52 #define ADISC 0x52
#define RNC 0x53 #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 * PRLI Word 3 definitions
* FPC4-r02b January, 2011 * FPC4-r02b January, 2011

View File

@ -1384,6 +1384,7 @@ typedef struct {
*/ */
typedef struct { typedef struct {
uint16_t handle; uint16_t handle;
uint16_t prli_word0;
uint16_t prli_word3; uint16_t prli_word3;
uint32_t : 8, uint32_t : 8,
portid : 24; portid : 24;

View File

@ -381,6 +381,9 @@ typedef struct {
uint16_t handle; 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. * PRLI word 3 parameters contains role as well as other things.
* *
* The state is the current state of this entry. * 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 * Portid is obvious, as are node && port WWNs. The new_role and
* new_portid is for when we are pending a change. * new_portid is for when we are pending a change.
*/ */
uint16_t prli_word0; /* PRLI parameters */
uint16_t prli_word3; /* 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 new_prli_word3; /* Incoming new PRLI parameters */
uint16_t : 12, uint16_t : 12,
probational : 1, probational : 1,

View File

@ -2211,7 +2211,8 @@ iwm_parse_nvm_data(struct iwm_softc *sc,
} }
if (sc->cfg->device_family == IWM_DEVICE_FAMILY_7000) { 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 ?
&regulatory[0] : &nvm_sw[IWM_NVM_CHANNELS],
IWM_NUM_CHANNELS * sizeof(uint16_t)); IWM_NUM_CHANNELS * sizeof(uint16_t));
} else { } else {
memcpy(data->nvm_ch_flags, &regulatory[IWM_NVM_CHANNELS_8000], memcpy(data->nvm_ch_flags, &regulatory[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; sw = (const uint16_t *)sections[IWM_NVM_SECTION_TYPE_SW].data;
calib = (const uint16_t *) calib = (const uint16_t *)
sections[IWM_NVM_SECTION_TYPE_CALIBRATION].data; sections[IWM_NVM_SECTION_TYPE_CALIBRATION].data;
regulatory = (const uint16_t *) regulatory = sc->cfg->nvm_type == IWM_NVM_SDP ?
sections[IWM_NVM_SECTION_TYPE_REGULATORY].data; (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 *) mac_override = (const uint16_t *)
sections[IWM_NVM_SECTION_TYPE_MAC_OVERRIDE].data; sections[IWM_NVM_SECTION_TYPE_MAC_OVERRIDE].data;
phy_sku = (const uint16_t *)sections[IWM_NVM_SECTION_TYPE_PHY_SKU].data; phy_sku = (const uint16_t *)sections[IWM_NVM_SECTION_TYPE_PHY_SKU].data;

View File

@ -119,6 +119,7 @@ const struct iwm_cfg iwm3168_cfg = {
.fw_name = IWM3168_FW, .fw_name = IWM3168_FW,
IWM_DEVICE_7000_COMMON, IWM_DEVICE_7000_COMMON,
.host_interrupt_operation_mode = 0, .host_interrupt_operation_mode = 0,
.nvm_type = IWM_NVM_SDP,
}; };
const struct iwm_cfg iwm7265_cfg = { const struct iwm_cfg iwm7265_cfg = {

View File

@ -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_8000 (32 * 512 * sizeof(uint16_t)) /* 32 KB */
#define IWM_OTP_LOW_IMAGE_SIZE_FAMILY_9000 IWM_OTP_LOW_IMAGE_SIZE_FAMILY_8000 #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 * struct iwm_cfg
* @name: Official name of the device * @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 * @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 * @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. * 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 { struct iwm_cfg {
const char *name; const char *name;
@ -122,6 +136,7 @@ struct iwm_cfg {
int host_interrupt_operation_mode; int host_interrupt_operation_mode;
uint8_t nvm_hw_section_num; uint8_t nvm_hw_section_num;
int apmg_wake_up_wa; int apmg_wake_up_wa;
enum iwm_nvm_type nvm_type;
}; };
/* /*

View File

@ -2032,6 +2032,7 @@ enum {
IWM_NVM_SECTION_TYPE_REGULATORY = 3, IWM_NVM_SECTION_TYPE_REGULATORY = 3,
IWM_NVM_SECTION_TYPE_CALIBRATION = 4, IWM_NVM_SECTION_TYPE_CALIBRATION = 4,
IWM_NVM_SECTION_TYPE_PRODUCTION = 5, IWM_NVM_SECTION_TYPE_PRODUCTION = 5,
IWM_NVM_SECTION_TYPE_REGULATORY_SDP = 8,
IWM_NVM_SECTION_TYPE_MAC_OVERRIDE = 11, IWM_NVM_SECTION_TYPE_MAC_OVERRIDE = 11,
IWM_NVM_SECTION_TYPE_PHY_SKU = 12, IWM_NVM_SECTION_TYPE_PHY_SKU = 12,
IWM_NVM_MAX_NUM_SECTIONS = 13, IWM_NVM_MAX_NUM_SECTIONS = 13,

View File

@ -2490,6 +2490,7 @@ int mlx4_cmd_init(struct mlx4_dev *dev)
init_rwsem(&priv->cmd.switch_sem); init_rwsem(&priv->cmd.switch_sem);
mutex_init(&priv->cmd.slave_cmd_mutex); mutex_init(&priv->cmd.slave_cmd_mutex);
sema_init(&priv->cmd.poll_sem, 1); sema_init(&priv->cmd.poll_sem, 1);
sema_init(&priv->cmd.event_sem, 0);
priv->cmd.use_events = 0; priv->cmd.use_events = 0;
priv->cmd.toggle = 1; priv->cmd.toggle = 1;
priv->cmd.initialized = 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); struct mlx4_priv *priv = mlx4_priv(dev);
int i; int i;
int err = 0;
if (priv->cmd.use_events != 0)
return 0;
priv->cmd.context = kmalloc(priv->cmd.max_cmds * priv->cmd.context = kmalloc(priv->cmd.max_cmds *
sizeof (struct mlx4_cmd_context), 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.context[priv->cmd.max_cmds - 1].next = -1;
priv->cmd.free_head = 0; 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; for (priv->cmd.token_mask = 1;
priv->cmd.token_mask < priv->cmd.max_cmds; 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; priv->cmd.use_events = 1;
up_write(&priv->cmd.switch_sem); 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); struct mlx4_priv *priv = mlx4_priv(dev);
int i; int i;
if (priv->cmd.use_events == 0)
return;
down_write(&priv->cmd.switch_sem); down_write(&priv->cmd.switch_sem);
priv->cmd.use_events = 0; priv->cmd.use_events = 0;
@ -2669,6 +2676,7 @@ void mlx4_cmd_use_polling(struct mlx4_dev *dev)
down(&priv->cmd.event_sem); down(&priv->cmd.event_sem);
kfree(priv->cmd.context); kfree(priv->cmd.context);
priv->cmd.context = NULL;
up(&priv->cmd.poll_sem); up(&priv->cmd.poll_sem);
up_write(&priv->cmd.switch_sem); up_write(&priv->cmd.switch_sem);
@ -2740,11 +2748,11 @@ void mlx4_cmd_wake_completions(struct mlx4_dev *dev)
int i; int i;
spin_lock(&priv->cmd.context_lock); spin_lock(&priv->cmd.context_lock);
if (priv->cmd.context) { if (priv->cmd.context != NULL) {
for (i = 0; i < priv->cmd.max_cmds; ++i) { for (i = 0; i < priv->cmd.max_cmds; ++i) {
context = &priv->cmd.context[i]; context = &priv->cmd.context[i];
context->fw_status = CMD_STAT_INTERNAL_ERR; context->fw_status = CMD_STAT_INTERNAL_ERR;
context->result = context->result =
mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR);
complete(&context->done); complete(&context->done);
} }

View File

@ -1236,9 +1236,6 @@ static ssize_t show_port_ib_mtu(struct device *dev,
port_mtu_attr); port_mtu_attr);
struct mlx4_dev *mdev = info->dev; 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", sprintf(buf, "%d\n",
ibta_mtu_to_int(mdev->caps.port_ib_mtu[info->port])); ibta_mtu_to_int(mdev->caps.port_ib_mtu[info->port]));
return strlen(buf); return strlen(buf);

View File

@ -1874,7 +1874,9 @@ tiNumOfLunIOCTLreq(
agSSPFrame->dataLength = REPORT_LUN_LEN; agSSPFrame->dataLength = REPORT_LUN_LEN;
agSSPFrame->agSgl.len = sizeof(agsaSSPCmdInfoUnit_t); 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, status = saSSPStart(agRoot, agIORequest, 0, agDevHandle, agRequestType,agSASRequestBody,agNULL,
&ossaSSPIoctlCompleted); &ossaSSPIoctlCompleted);
if(status != AGSA_RC_SUCCESS) if(status != AGSA_RC_SUCCESS)

View File

@ -2258,9 +2258,6 @@ nandfs_pathconf(struct vop_pathconf_args *ap)
case _PC_NO_TRUNC: case _PC_NO_TRUNC:
*ap->a_retval = 1; *ap->a_retval = 1;
break; break;
case _PC_ACL_EXTENDED:
*ap->a_retval = 0;
break;
case _PC_ALLOC_SIZE_MIN: case _PC_ALLOC_SIZE_MIN:
*ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_bsize; *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_bsize;
break; break;

View File

@ -3511,9 +3511,6 @@ nfs_pathconf(struct vop_pathconf_args *ap)
case _PC_NO_TRUNC: case _PC_NO_TRUNC:
*ap->a_retval = pc.pc_notrunc; *ap->a_retval = pc.pc_notrunc;
break; break;
case _PC_ACL_EXTENDED:
*ap->a_retval = 0;
break;
case _PC_ACL_NFS4: case _PC_ACL_NFS4:
if (NFS_ISV4(vp) && nfsrv_useacl != 0 && attrflag != 0 && if (NFS_ISV4(vp) && nfsrv_useacl != 0 && attrflag != 0 &&
NFSISSET_ATTRBIT(&nfsva.na_suppattr, NFSATTRBIT_ACL)) NFSISSET_ATTRBIT(&nfsva.na_suppattr, NFSATTRBIT_ACL))
@ -3527,9 +3524,6 @@ nfs_pathconf(struct vop_pathconf_args *ap)
else else
*ap->a_retval = 3; *ap->a_retval = 3;
break; break;
case _PC_MAC_PRESENT:
*ap->a_retval = 0;
break;
case _PC_PRIO_IO: case _PC_PRIO_IO:
*ap->a_retval = 0; *ap->a_retval = 0;
break; break;

View File

@ -482,6 +482,13 @@ vop_stdpathconf(ap)
case _PC_PATH_MAX: case _PC_PATH_MAX:
*ap->a_retval = PATH_MAX; *ap->a_retval = PATH_MAX;
return (0); 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: default:
return (EINVAL); return (EINVAL);
} }

View File

@ -313,6 +313,10 @@ ipfw_check_packet(struct mbuf **m0, struct ifnet *ifp, int dir,
case IP_FW_REASS: case IP_FW_REASS:
goto again; /* continue with packet */ goto again; /* continue with packet */
case IP_FW_NAT64:
ret = PFIL_CONSUMED;
break;
default: default:
KASSERT(0, ("%s: unknown retval", __func__)); KASSERT(0, ("%s: unknown retval", __func__));
} }

View File

@ -61,6 +61,7 @@ enum {
IP_FW_NGTEE, IP_FW_NGTEE,
IP_FW_NAT, IP_FW_NAT,
IP_FW_REASS, IP_FW_REASS,
IP_FW_NAT64,
}; };
/* /*

View File

@ -219,6 +219,8 @@ nat64_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
} }
if (logdata != NULL) if (logdata != NULL)
nat64_log(logdata, m, af); nat64_log(logdata, m, af);
if (m->m_pkthdr.rcvif == NULL)
m->m_pkthdr.rcvif = V_loif;
ret = netisr_queue(ret, m); ret = netisr_queue(ret, m);
if (ret != 0) if (ret != 0)
NAT64STAT_INC(stats, oerrors); NAT64STAT_INC(stats, oerrors);

View File

@ -2421,28 +2421,20 @@ ufs_pathconf(ap)
case _PC_NO_TRUNC: case _PC_NO_TRUNC:
*ap->a_retval = 1; *ap->a_retval = 1;
break; break;
case _PC_ACL_EXTENDED:
#ifdef UFS_ACL #ifdef UFS_ACL
case _PC_ACL_EXTENDED:
if (ap->a_vp->v_mount->mnt_flag & MNT_ACLS) if (ap->a_vp->v_mount->mnt_flag & MNT_ACLS)
*ap->a_retval = 1; *ap->a_retval = 1;
else else
*ap->a_retval = 0; *ap->a_retval = 0;
#else
*ap->a_retval = 0;
#endif
break; break;
case _PC_ACL_NFS4: case _PC_ACL_NFS4:
#ifdef UFS_ACL
if (ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) if (ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS)
*ap->a_retval = 1; *ap->a_retval = 1;
else else
*ap->a_retval = 0; *ap->a_retval = 0;
#else
*ap->a_retval = 0;
#endif
break; break;
#endif
case _PC_ACL_PATH_MAX: case _PC_ACL_PATH_MAX:
#ifdef UFS_ACL #ifdef UFS_ACL
if (ap->a_vp->v_mount->mnt_flag & (MNT_ACLS | MNT_NFS4ACLS)) if (ap->a_vp->v_mount->mnt_flag & (MNT_ACLS | MNT_NFS4ACLS))
@ -2453,16 +2445,14 @@ ufs_pathconf(ap)
*ap->a_retval = 3; *ap->a_retval = 3;
#endif #endif
break; break;
case _PC_MAC_PRESENT:
#ifdef MAC #ifdef MAC
case _PC_MAC_PRESENT:
if (ap->a_vp->v_mount->mnt_flag & MNT_MULTILABEL) if (ap->a_vp->v_mount->mnt_flag & MNT_MULTILABEL)
*ap->a_retval = 1; *ap->a_retval = 1;
else else
*ap->a_retval = 0; *ap->a_retval = 0;
#else
*ap->a_retval = 0;
#endif
break; break;
#endif
case _PC_MIN_HOLE_SIZE: case _PC_MIN_HOLE_SIZE:
*ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize; *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize;
break; break;

View File

@ -83,6 +83,11 @@ static int rtc_reg = -1;
static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
static u_char rtc_statusb = RTCSB_24HR; static u_char rtc_statusb = RTCSB_24HR;
#ifdef DEV_ACPI
#define _COMPONENT ACPI_TIMER
ACPI_MODULE_NAME("ATRTC")
#endif
/* /*
* RTC support routines * RTC support routines
*/ */