mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-04 12:52:15 +00:00
Merge LLVM libunwind trunk r351319, from just before upstream's
release_80 branch point. Afterwards, we will merge the rest of the changes in the actual release_80 branch. PR: 236062 MFC after: 1 month X-MFC-With: r344779
This commit is contained in:
commit
30622d9f9e
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=345018
76
contrib/llvm/projects/libunwind/LICENSE.TXT
Normal file
76
contrib/llvm/projects/libunwind/LICENSE.TXT
Normal 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.
|
@ -12,65 +12,101 @@
|
||||
|
||||
#if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \
|
||||
!defined(__ARM_DWARF_EH__)
|
||||
#define _LIBUNWIND_ARM_EHABI 1
|
||||
#else
|
||||
#define _LIBUNWIND_ARM_EHABI 0
|
||||
#define _LIBUNWIND_ARM_EHABI
|
||||
#endif
|
||||
|
||||
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86 8
|
||||
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64 32
|
||||
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC 112
|
||||
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64 116
|
||||
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64 95
|
||||
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM 287
|
||||
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K 32
|
||||
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV 95
|
||||
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS 65
|
||||
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC 31
|
||||
|
||||
#if defined(_LIBUNWIND_IS_NATIVE_ONLY)
|
||||
# if defined(__i386__)
|
||||
# define _LIBUNWIND_TARGET_I386 1
|
||||
# define _LIBUNWIND_TARGET_I386
|
||||
# define _LIBUNWIND_CONTEXT_SIZE 8
|
||||
# define _LIBUNWIND_CURSOR_SIZE 19
|
||||
# define _LIBUNWIND_MAX_REGISTER 9
|
||||
# define _LIBUNWIND_CURSOR_SIZE 15
|
||||
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86
|
||||
# elif defined(__x86_64__)
|
||||
# define _LIBUNWIND_TARGET_X86_64 1
|
||||
# define _LIBUNWIND_CONTEXT_SIZE 21
|
||||
# define _LIBUNWIND_CURSOR_SIZE 33
|
||||
# define _LIBUNWIND_MAX_REGISTER 17
|
||||
# if defined(_WIN64)
|
||||
# define _LIBUNWIND_CONTEXT_SIZE 54
|
||||
# ifdef __SEH__
|
||||
# define _LIBUNWIND_CURSOR_SIZE 204
|
||||
# else
|
||||
# define _LIBUNWIND_CURSOR_SIZE 66
|
||||
# endif
|
||||
# else
|
||||
# define _LIBUNWIND_CONTEXT_SIZE 21
|
||||
# define _LIBUNWIND_CURSOR_SIZE 33
|
||||
# endif
|
||||
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64
|
||||
# elif defined(__powerpc64__)
|
||||
# define _LIBUNWIND_TARGET_PPC64 1
|
||||
# define _LIBUNWIND_CONTEXT_SIZE 167
|
||||
# define _LIBUNWIND_CURSOR_SIZE 179
|
||||
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64
|
||||
# elif defined(__ppc__)
|
||||
# define _LIBUNWIND_TARGET_PPC 1
|
||||
# define _LIBUNWIND_CONTEXT_SIZE 117
|
||||
# define _LIBUNWIND_CURSOR_SIZE 128
|
||||
# define _LIBUNWIND_MAX_REGISTER 113
|
||||
# define _LIBUNWIND_CURSOR_SIZE 124
|
||||
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC
|
||||
# elif defined(__aarch64__)
|
||||
# define _LIBUNWIND_TARGET_AARCH64 1
|
||||
# define _LIBUNWIND_CONTEXT_SIZE 66
|
||||
# define _LIBUNWIND_CURSOR_SIZE 78
|
||||
# define _LIBUNWIND_MAX_REGISTER 96
|
||||
# if defined(__SEH__)
|
||||
# define _LIBUNWIND_CURSOR_SIZE 164
|
||||
# else
|
||||
# define _LIBUNWIND_CURSOR_SIZE 78
|
||||
# endif
|
||||
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64
|
||||
# elif defined(__arm__)
|
||||
# define _LIBUNWIND_TARGET_ARM 1
|
||||
# define _LIBUNWIND_CONTEXT_SIZE 60
|
||||
# define _LIBUNWIND_CURSOR_SIZE 67
|
||||
# define _LIBUNWIND_MAX_REGISTER 96
|
||||
# if defined(__SEH__)
|
||||
# define _LIBUNWIND_CONTEXT_SIZE 42
|
||||
# define _LIBUNWIND_CURSOR_SIZE 80
|
||||
# elif defined(__ARM_WMMX)
|
||||
# define _LIBUNWIND_CONTEXT_SIZE 61
|
||||
# define _LIBUNWIND_CURSOR_SIZE 68
|
||||
# else
|
||||
# define _LIBUNWIND_CONTEXT_SIZE 42
|
||||
# define _LIBUNWIND_CURSOR_SIZE 49
|
||||
# endif
|
||||
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM
|
||||
# elif defined(__or1k__)
|
||||
# define _LIBUNWIND_TARGET_OR1K 1
|
||||
# define _LIBUNWIND_CONTEXT_SIZE 16
|
||||
# define _LIBUNWIND_CURSOR_SIZE 28
|
||||
# define _LIBUNWIND_MAX_REGISTER 32
|
||||
# define _LIBUNWIND_CURSOR_SIZE 24
|
||||
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K
|
||||
# elif defined(__riscv)
|
||||
# define _LIBUNWIND_TARGET_RISCV 1
|
||||
# define _LIBUNWIND_CONTEXT_SIZE 64
|
||||
# define _LIBUNWIND_CURSOR_SIZE 76
|
||||
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV
|
||||
# define _LIBUNWIND_MAX_REGISTER 96
|
||||
# elif defined(__mips__)
|
||||
# if defined(_ABIO32) && _MIPS_SIM == _ABIO32
|
||||
# define _LIBUNWIND_TARGET_MIPS_O32 1
|
||||
# if defined(__mips_hard_float)
|
||||
# define _LIBUNWIND_CONTEXT_SIZE 50
|
||||
# define _LIBUNWIND_CURSOR_SIZE 61
|
||||
# define _LIBUNWIND_CURSOR_SIZE 57
|
||||
# else
|
||||
# define _LIBUNWIND_CONTEXT_SIZE 18
|
||||
# define _LIBUNWIND_CURSOR_SIZE 29
|
||||
# define _LIBUNWIND_CURSOR_SIZE 24
|
||||
# endif
|
||||
# elif defined(_ABIN32) && _MIPS_SIM == _ABIN32
|
||||
# define _LIBUNWIND_TARGET_MIPS_NEWABI 1
|
||||
# if defined(__mips_hard_float)
|
||||
# define _LIBUNWIND_CONTEXT_SIZE 67
|
||||
# define _LIBUNWIND_CURSOR_SIZE 78
|
||||
# define _LIBUNWIND_CURSOR_SIZE 74
|
||||
# else
|
||||
# define _LIBUNWIND_CONTEXT_SIZE 35
|
||||
# define _LIBUNWIND_CURSOR_SIZE 46
|
||||
# define _LIBUNWIND_CURSOR_SIZE 42
|
||||
# endif
|
||||
# elif defined(_ABI64) && _MIPS_SIM == _ABI64
|
||||
# define _LIBUNWIND_TARGET_MIPS_NEWABI 1
|
||||
@ -84,22 +120,29 @@
|
||||
# else
|
||||
# error "Unsupported MIPS ABI and/or environment"
|
||||
# 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
|
||||
# error "Unsupported architecture."
|
||||
# endif
|
||||
#else // !_LIBUNWIND_IS_NATIVE_ONLY
|
||||
# define _LIBUNWIND_TARGET_I386 1
|
||||
# define _LIBUNWIND_TARGET_I386
|
||||
# define _LIBUNWIND_TARGET_X86_64 1
|
||||
# define _LIBUNWIND_TARGET_PPC 1
|
||||
# define _LIBUNWIND_TARGET_PPC64 1
|
||||
# define _LIBUNWIND_TARGET_AARCH64 1
|
||||
# define _LIBUNWIND_TARGET_ARM 1
|
||||
# define _LIBUNWIND_TARGET_OR1K 1
|
||||
# define _LIBUNWIND_TARGET_MIPS_O32 1
|
||||
# define _LIBUNWIND_TARGET_MIPS_NEWABI 1
|
||||
# define _LIBUNWIND_CONTEXT_SIZE 128
|
||||
# define _LIBUNWIND_CURSOR_SIZE 140
|
||||
# define _LIBUNWIND_MAX_REGISTER 120
|
||||
# define _LIBUNWIND_TARGET_SPARC 1
|
||||
# define _LIBUNWIND_CONTEXT_SIZE 167
|
||||
# define _LIBUNWIND_CURSOR_SIZE 179
|
||||
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287
|
||||
#endif // _LIBUNWIND_IS_NATIVE_ONLY
|
||||
|
||||
#endif // ____LIBUNWIND_CONFIG_H__
|
||||
|
@ -20,12 +20,26 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <Availability.h>
|
||||
#ifdef __arm__
|
||||
#define LIBUNWIND_AVAIL __attribute__((unavailable))
|
||||
#else
|
||||
#define LIBUNWIND_AVAIL __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_5_0)
|
||||
#if __clang__
|
||||
#if __has_include(<Availability.h>)
|
||||
#include <Availability.h>
|
||||
#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
|
||||
#define LIBUNWIND_AVAIL
|
||||
#endif
|
||||
@ -43,6 +57,9 @@ enum {
|
||||
UNW_EINVAL = -6547, /* unsupported operation or bad value */
|
||||
UNW_EBADVERSION = -6548, /* unwind info has unsupported version */
|
||||
UNW_ENOINFO = -6549 /* no unwind info found */
|
||||
#if defined(_LIBUNWIND_TARGET_AARCH64) && !defined(_LIBUNWIND_IS_NATIVE_ONLY)
|
||||
, UNW_ECROSSRASIGNING = -6550 /* cross unwind with return address signing */
|
||||
#endif
|
||||
};
|
||||
|
||||
struct unw_context_t {
|
||||
@ -58,11 +75,10 @@ typedef struct unw_cursor_t unw_cursor_t;
|
||||
typedef struct unw_addr_space *unw_addr_space_t;
|
||||
|
||||
typedef int unw_regnum_t;
|
||||
#if _LIBUNWIND_ARM_EHABI
|
||||
typedef uint32_t unw_word_t;
|
||||
typedef uintptr_t unw_word_t;
|
||||
#if defined(__arm__)
|
||||
typedef uint64_t unw_fpreg_t;
|
||||
#else
|
||||
typedef uint64_t unw_word_t;
|
||||
typedef double unw_fpreg_t;
|
||||
#endif
|
||||
|
||||
@ -75,8 +91,8 @@ struct unw_proc_info_t {
|
||||
unw_word_t gp; /* not used */
|
||||
unw_word_t flags; /* not used */
|
||||
uint32_t format; /* compact unwind encoding, or zero if none */
|
||||
uint32_t unwind_info_size; /* size of dwarf unwind info, or zero if none */
|
||||
unw_word_t unwind_info; /* address of dwarf unwind info, or zero */
|
||||
uint32_t unwind_info_size; /* size of DWARF unwind info, or zero if none */
|
||||
unw_word_t unwind_info; /* address of DWARF unwind info, or zero */
|
||||
unw_word_t extra; /* mach_header of mach-o image containing func */
|
||||
};
|
||||
typedef struct unw_proc_info_t unw_proc_info_t;
|
||||
@ -151,8 +167,8 @@ enum {
|
||||
UNW_X86_ECX = 1,
|
||||
UNW_X86_EDX = 2,
|
||||
UNW_X86_EBX = 3,
|
||||
UNW_X86_ESP = 4,
|
||||
UNW_X86_EBP = 5,
|
||||
UNW_X86_EBP = 4,
|
||||
UNW_X86_ESP = 5,
|
||||
UNW_X86_ESI = 6,
|
||||
UNW_X86_EDI = 7
|
||||
};
|
||||
@ -174,7 +190,24 @@ enum {
|
||||
UNW_X86_64_R12 = 12,
|
||||
UNW_X86_64_R13 = 13,
|
||||
UNW_X86_64_R14 = 14,
|
||||
UNW_X86_64_R15 = 15
|
||||
UNW_X86_64_R15 = 15,
|
||||
UNW_X86_64_RIP = 16,
|
||||
UNW_X86_64_XMM0 = 17,
|
||||
UNW_X86_64_XMM1 = 18,
|
||||
UNW_X86_64_XMM2 = 19,
|
||||
UNW_X86_64_XMM3 = 20,
|
||||
UNW_X86_64_XMM4 = 21,
|
||||
UNW_X86_64_XMM5 = 22,
|
||||
UNW_X86_64_XMM6 = 23,
|
||||
UNW_X86_64_XMM7 = 24,
|
||||
UNW_X86_64_XMM8 = 25,
|
||||
UNW_X86_64_XMM9 = 26,
|
||||
UNW_X86_64_XMM10 = 27,
|
||||
UNW_X86_64_XMM11 = 28,
|
||||
UNW_X86_64_XMM12 = 29,
|
||||
UNW_X86_64_XMM13 = 30,
|
||||
UNW_X86_64_XMM14 = 31,
|
||||
UNW_X86_64_XMM15 = 32,
|
||||
};
|
||||
|
||||
|
||||
@ -295,6 +328,190 @@ enum {
|
||||
UNW_PPC_SPEFSCR = 112
|
||||
};
|
||||
|
||||
// 64-bit ppc register numbers
|
||||
enum {
|
||||
UNW_PPC64_R0 = 0,
|
||||
UNW_PPC64_R1 = 1,
|
||||
UNW_PPC64_R2 = 2,
|
||||
UNW_PPC64_R3 = 3,
|
||||
UNW_PPC64_R4 = 4,
|
||||
UNW_PPC64_R5 = 5,
|
||||
UNW_PPC64_R6 = 6,
|
||||
UNW_PPC64_R7 = 7,
|
||||
UNW_PPC64_R8 = 8,
|
||||
UNW_PPC64_R9 = 9,
|
||||
UNW_PPC64_R10 = 10,
|
||||
UNW_PPC64_R11 = 11,
|
||||
UNW_PPC64_R12 = 12,
|
||||
UNW_PPC64_R13 = 13,
|
||||
UNW_PPC64_R14 = 14,
|
||||
UNW_PPC64_R15 = 15,
|
||||
UNW_PPC64_R16 = 16,
|
||||
UNW_PPC64_R17 = 17,
|
||||
UNW_PPC64_R18 = 18,
|
||||
UNW_PPC64_R19 = 19,
|
||||
UNW_PPC64_R20 = 20,
|
||||
UNW_PPC64_R21 = 21,
|
||||
UNW_PPC64_R22 = 22,
|
||||
UNW_PPC64_R23 = 23,
|
||||
UNW_PPC64_R24 = 24,
|
||||
UNW_PPC64_R25 = 25,
|
||||
UNW_PPC64_R26 = 26,
|
||||
UNW_PPC64_R27 = 27,
|
||||
UNW_PPC64_R28 = 28,
|
||||
UNW_PPC64_R29 = 29,
|
||||
UNW_PPC64_R30 = 30,
|
||||
UNW_PPC64_R31 = 31,
|
||||
UNW_PPC64_F0 = 32,
|
||||
UNW_PPC64_F1 = 33,
|
||||
UNW_PPC64_F2 = 34,
|
||||
UNW_PPC64_F3 = 35,
|
||||
UNW_PPC64_F4 = 36,
|
||||
UNW_PPC64_F5 = 37,
|
||||
UNW_PPC64_F6 = 38,
|
||||
UNW_PPC64_F7 = 39,
|
||||
UNW_PPC64_F8 = 40,
|
||||
UNW_PPC64_F9 = 41,
|
||||
UNW_PPC64_F10 = 42,
|
||||
UNW_PPC64_F11 = 43,
|
||||
UNW_PPC64_F12 = 44,
|
||||
UNW_PPC64_F13 = 45,
|
||||
UNW_PPC64_F14 = 46,
|
||||
UNW_PPC64_F15 = 47,
|
||||
UNW_PPC64_F16 = 48,
|
||||
UNW_PPC64_F17 = 49,
|
||||
UNW_PPC64_F18 = 50,
|
||||
UNW_PPC64_F19 = 51,
|
||||
UNW_PPC64_F20 = 52,
|
||||
UNW_PPC64_F21 = 53,
|
||||
UNW_PPC64_F22 = 54,
|
||||
UNW_PPC64_F23 = 55,
|
||||
UNW_PPC64_F24 = 56,
|
||||
UNW_PPC64_F25 = 57,
|
||||
UNW_PPC64_F26 = 58,
|
||||
UNW_PPC64_F27 = 59,
|
||||
UNW_PPC64_F28 = 60,
|
||||
UNW_PPC64_F29 = 61,
|
||||
UNW_PPC64_F30 = 62,
|
||||
UNW_PPC64_F31 = 63,
|
||||
// 64: reserved
|
||||
UNW_PPC64_LR = 65,
|
||||
UNW_PPC64_CTR = 66,
|
||||
// 67: reserved
|
||||
UNW_PPC64_CR0 = 68,
|
||||
UNW_PPC64_CR1 = 69,
|
||||
UNW_PPC64_CR2 = 70,
|
||||
UNW_PPC64_CR3 = 71,
|
||||
UNW_PPC64_CR4 = 72,
|
||||
UNW_PPC64_CR5 = 73,
|
||||
UNW_PPC64_CR6 = 74,
|
||||
UNW_PPC64_CR7 = 75,
|
||||
UNW_PPC64_XER = 76,
|
||||
UNW_PPC64_V0 = 77,
|
||||
UNW_PPC64_V1 = 78,
|
||||
UNW_PPC64_V2 = 79,
|
||||
UNW_PPC64_V3 = 80,
|
||||
UNW_PPC64_V4 = 81,
|
||||
UNW_PPC64_V5 = 82,
|
||||
UNW_PPC64_V6 = 83,
|
||||
UNW_PPC64_V7 = 84,
|
||||
UNW_PPC64_V8 = 85,
|
||||
UNW_PPC64_V9 = 86,
|
||||
UNW_PPC64_V10 = 87,
|
||||
UNW_PPC64_V11 = 88,
|
||||
UNW_PPC64_V12 = 89,
|
||||
UNW_PPC64_V13 = 90,
|
||||
UNW_PPC64_V14 = 91,
|
||||
UNW_PPC64_V15 = 92,
|
||||
UNW_PPC64_V16 = 93,
|
||||
UNW_PPC64_V17 = 94,
|
||||
UNW_PPC64_V18 = 95,
|
||||
UNW_PPC64_V19 = 96,
|
||||
UNW_PPC64_V20 = 97,
|
||||
UNW_PPC64_V21 = 98,
|
||||
UNW_PPC64_V22 = 99,
|
||||
UNW_PPC64_V23 = 100,
|
||||
UNW_PPC64_V24 = 101,
|
||||
UNW_PPC64_V25 = 102,
|
||||
UNW_PPC64_V26 = 103,
|
||||
UNW_PPC64_V27 = 104,
|
||||
UNW_PPC64_V28 = 105,
|
||||
UNW_PPC64_V29 = 106,
|
||||
UNW_PPC64_V30 = 107,
|
||||
UNW_PPC64_V31 = 108,
|
||||
// 109, 111-113: OpenPOWER ELF V2 ABI: reserved
|
||||
// Borrowing VRSAVE number from PPC32.
|
||||
UNW_PPC64_VRSAVE = 109,
|
||||
UNW_PPC64_VSCR = 110,
|
||||
UNW_PPC64_TFHAR = 114,
|
||||
UNW_PPC64_TFIAR = 115,
|
||||
UNW_PPC64_TEXASR = 116,
|
||||
UNW_PPC64_VS0 = UNW_PPC64_F0,
|
||||
UNW_PPC64_VS1 = UNW_PPC64_F1,
|
||||
UNW_PPC64_VS2 = UNW_PPC64_F2,
|
||||
UNW_PPC64_VS3 = UNW_PPC64_F3,
|
||||
UNW_PPC64_VS4 = UNW_PPC64_F4,
|
||||
UNW_PPC64_VS5 = UNW_PPC64_F5,
|
||||
UNW_PPC64_VS6 = UNW_PPC64_F6,
|
||||
UNW_PPC64_VS7 = UNW_PPC64_F7,
|
||||
UNW_PPC64_VS8 = UNW_PPC64_F8,
|
||||
UNW_PPC64_VS9 = UNW_PPC64_F9,
|
||||
UNW_PPC64_VS10 = UNW_PPC64_F10,
|
||||
UNW_PPC64_VS11 = UNW_PPC64_F11,
|
||||
UNW_PPC64_VS12 = UNW_PPC64_F12,
|
||||
UNW_PPC64_VS13 = UNW_PPC64_F13,
|
||||
UNW_PPC64_VS14 = UNW_PPC64_F14,
|
||||
UNW_PPC64_VS15 = UNW_PPC64_F15,
|
||||
UNW_PPC64_VS16 = UNW_PPC64_F16,
|
||||
UNW_PPC64_VS17 = UNW_PPC64_F17,
|
||||
UNW_PPC64_VS18 = UNW_PPC64_F18,
|
||||
UNW_PPC64_VS19 = UNW_PPC64_F19,
|
||||
UNW_PPC64_VS20 = UNW_PPC64_F20,
|
||||
UNW_PPC64_VS21 = UNW_PPC64_F21,
|
||||
UNW_PPC64_VS22 = UNW_PPC64_F22,
|
||||
UNW_PPC64_VS23 = UNW_PPC64_F23,
|
||||
UNW_PPC64_VS24 = UNW_PPC64_F24,
|
||||
UNW_PPC64_VS25 = UNW_PPC64_F25,
|
||||
UNW_PPC64_VS26 = UNW_PPC64_F26,
|
||||
UNW_PPC64_VS27 = UNW_PPC64_F27,
|
||||
UNW_PPC64_VS28 = UNW_PPC64_F28,
|
||||
UNW_PPC64_VS29 = UNW_PPC64_F29,
|
||||
UNW_PPC64_VS30 = UNW_PPC64_F30,
|
||||
UNW_PPC64_VS31 = UNW_PPC64_F31,
|
||||
UNW_PPC64_VS32 = UNW_PPC64_V0,
|
||||
UNW_PPC64_VS33 = UNW_PPC64_V1,
|
||||
UNW_PPC64_VS34 = UNW_PPC64_V2,
|
||||
UNW_PPC64_VS35 = UNW_PPC64_V3,
|
||||
UNW_PPC64_VS36 = UNW_PPC64_V4,
|
||||
UNW_PPC64_VS37 = UNW_PPC64_V5,
|
||||
UNW_PPC64_VS38 = UNW_PPC64_V6,
|
||||
UNW_PPC64_VS39 = UNW_PPC64_V7,
|
||||
UNW_PPC64_VS40 = UNW_PPC64_V8,
|
||||
UNW_PPC64_VS41 = UNW_PPC64_V9,
|
||||
UNW_PPC64_VS42 = UNW_PPC64_V10,
|
||||
UNW_PPC64_VS43 = UNW_PPC64_V11,
|
||||
UNW_PPC64_VS44 = UNW_PPC64_V12,
|
||||
UNW_PPC64_VS45 = UNW_PPC64_V13,
|
||||
UNW_PPC64_VS46 = UNW_PPC64_V14,
|
||||
UNW_PPC64_VS47 = UNW_PPC64_V15,
|
||||
UNW_PPC64_VS48 = UNW_PPC64_V16,
|
||||
UNW_PPC64_VS49 = UNW_PPC64_V17,
|
||||
UNW_PPC64_VS50 = UNW_PPC64_V18,
|
||||
UNW_PPC64_VS51 = UNW_PPC64_V19,
|
||||
UNW_PPC64_VS52 = UNW_PPC64_V20,
|
||||
UNW_PPC64_VS53 = UNW_PPC64_V21,
|
||||
UNW_PPC64_VS54 = UNW_PPC64_V22,
|
||||
UNW_PPC64_VS55 = UNW_PPC64_V23,
|
||||
UNW_PPC64_VS56 = UNW_PPC64_V24,
|
||||
UNW_PPC64_VS57 = UNW_PPC64_V25,
|
||||
UNW_PPC64_VS58 = UNW_PPC64_V26,
|
||||
UNW_PPC64_VS59 = UNW_PPC64_V27,
|
||||
UNW_PPC64_VS60 = UNW_PPC64_V28,
|
||||
UNW_PPC64_VS61 = UNW_PPC64_V29,
|
||||
UNW_PPC64_VS62 = UNW_PPC64_V30,
|
||||
UNW_PPC64_VS63 = UNW_PPC64_V31
|
||||
};
|
||||
|
||||
// 64-bit ARM64 registers
|
||||
enum {
|
||||
UNW_ARM64_X0 = 0,
|
||||
@ -333,6 +550,8 @@ enum {
|
||||
UNW_ARM64_X31 = 31,
|
||||
UNW_ARM64_SP = 31,
|
||||
// reserved block
|
||||
UNW_ARM64_RA_SIGN_STATE = 34,
|
||||
// reserved block
|
||||
UNW_ARM64_D0 = 64,
|
||||
UNW_ARM64_D1 = 65,
|
||||
UNW_ARM64_D2 = 66,
|
||||
@ -531,6 +750,7 @@ enum {
|
||||
UNW_OR1K_R29 = 29,
|
||||
UNW_OR1K_R30 = 30,
|
||||
UNW_OR1K_R31 = 31,
|
||||
UNW_OR1K_EPCR = 32,
|
||||
};
|
||||
|
||||
// 64-bit RISC-V registers
|
||||
@ -674,4 +894,40 @@ enum {
|
||||
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
|
||||
|
@ -6,7 +6,7 @@
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//
|
||||
// Darwin's alternative to dwarf based unwind encodings.
|
||||
// Darwin's alternative to DWARF based unwind encodings.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
#include <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
|
||||
// the __LD,__compact_unwind section.
|
||||
//
|
||||
@ -26,10 +26,10 @@
|
||||
// runtime to access unwind info for any given function. If the compiler
|
||||
// emitted compact unwind info for the function, that compact unwind info will
|
||||
// be encoded in the __TEXT,__unwind_info section. If the compiler emitted
|
||||
// dwarf unwind info, the __TEXT,__unwind_info section will contain the offset
|
||||
// DWARF unwind info, the __TEXT,__unwind_info section will contain the offset
|
||||
// of the FDE in the __TEXT,__eh_frame section in the final linked image.
|
||||
//
|
||||
// Note: Previously, the linker would transform some dwarf unwind infos into
|
||||
// Note: Previously, the linker would transform some DWARF unwind infos into
|
||||
// compact unwind info. But that is fragile and no longer done.
|
||||
|
||||
|
||||
@ -58,7 +58,7 @@ enum {
|
||||
// 1-bit: has lsda
|
||||
// 2-bit: personality index
|
||||
//
|
||||
// 4-bits: 0=old, 1=ebp based, 2=stack-imm, 3=stack-ind, 4=dwarf
|
||||
// 4-bits: 0=old, 1=ebp based, 2=stack-imm, 3=stack-ind, 4=DWARF
|
||||
// ebp based:
|
||||
// 15-bits (5*3-bits per reg) register permutation
|
||||
// 8-bits for stack offset
|
||||
@ -128,9 +128,9 @@ enum {
|
||||
// UNWIND_X86_FRAMELESS_STACK_SIZE.
|
||||
// UNWIND_X86_MODE_DWARF:
|
||||
// No compact unwind encoding is available. Instead the low 24-bits of the
|
||||
// compact encoding is the offset of the dwarf FDE in the __eh_frame section.
|
||||
// compact encoding is the offset of the DWARF FDE in the __eh_frame section.
|
||||
// This mode is never used in object files. It is only generated by the
|
||||
// linker in final linked images which have only dwarf unwind info for a
|
||||
// linker in final linked images which have only DWARF unwind info for a
|
||||
// function.
|
||||
//
|
||||
// The permutation encoding is a Lehmer code sequence encoded into a
|
||||
@ -193,7 +193,7 @@ enum {
|
||||
// 1-bit: has lsda
|
||||
// 2-bit: personality index
|
||||
//
|
||||
// 4-bits: 0=old, 1=rbp based, 2=stack-imm, 3=stack-ind, 4=dwarf
|
||||
// 4-bits: 0=old, 1=rbp based, 2=stack-imm, 3=stack-ind, 4=DWARF
|
||||
// rbp based:
|
||||
// 15-bits (5*3-bits per reg) register permutation
|
||||
// 8-bits for stack offset
|
||||
@ -262,9 +262,9 @@ enum {
|
||||
// UNWIND_X86_64_FRAMELESS_STACK_SIZE.
|
||||
// UNWIND_X86_64_MODE_DWARF:
|
||||
// No compact unwind encoding is available. Instead the low 24-bits of the
|
||||
// compact encoding is the offset of the dwarf FDE in the __eh_frame section.
|
||||
// compact encoding is the offset of the DWARF FDE in the __eh_frame section.
|
||||
// This mode is never used in object files. It is only generated by the
|
||||
// linker in final linked images which have only dwarf unwind info for a
|
||||
// linker in final linked images which have only DWARF unwind info for a
|
||||
// function.
|
||||
//
|
||||
|
||||
@ -275,14 +275,14 @@ enum {
|
||||
// 1-bit: has lsda
|
||||
// 2-bit: personality index
|
||||
//
|
||||
// 4-bits: 4=frame-based, 3=dwarf, 2=frameless
|
||||
// 4-bits: 4=frame-based, 3=DWARF, 2=frameless
|
||||
// frameless:
|
||||
// 12-bits of stack size
|
||||
// frame-based:
|
||||
// 4-bits D reg pairs saved
|
||||
// 5-bits X reg pairs saved
|
||||
// dwarf:
|
||||
// 24-bits offset of dwarf FDE in __eh_frame section
|
||||
// DWARF:
|
||||
// 24-bits offset of DWARF FDE in __eh_frame section
|
||||
//
|
||||
enum {
|
||||
UNWIND_ARM64_MODE_MASK = 0x0F000000,
|
||||
@ -320,9 +320,9 @@ enum {
|
||||
// UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK.
|
||||
// UNWIND_ARM64_MODE_DWARF:
|
||||
// No compact unwind encoding is available. Instead the low 24-bits of the
|
||||
// compact encoding is the offset of the dwarf FDE in the __eh_frame section.
|
||||
// compact encoding is the offset of the DWARF FDE in the __eh_frame section.
|
||||
// This mode is never used in object files. It is only generated by the
|
||||
// linker in final linked images which have only dwarf unwind info for a
|
||||
// linker in final linked images which have only DWARF unwind info for a
|
||||
// function.
|
||||
//
|
||||
|
||||
@ -385,7 +385,7 @@ enum {
|
||||
// saved at that range of the function.
|
||||
//
|
||||
// If a particular function is so wacky that there is no compact unwind way
|
||||
// to encode it, then the compiler can emit traditional dwarf unwind info.
|
||||
// to encode it, then the compiler can emit traditional DWARF unwind info.
|
||||
// The runtime will use which ever is available.
|
||||
//
|
||||
// Runtime support for compact unwind encodings are only available on 10.6
|
||||
|
@ -19,6 +19,11 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) && defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#include <ntverp.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#define LIBUNWIND_UNAVAIL __attribute__ (( unavailable ))
|
||||
#else
|
||||
@ -36,7 +41,7 @@ typedef enum {
|
||||
_URC_HANDLER_FOUND = 6,
|
||||
_URC_INSTALL_CONTEXT = 7,
|
||||
_URC_CONTINUE_UNWIND = 8,
|
||||
#if _LIBUNWIND_ARM_EHABI
|
||||
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||
_URC_FAILURE = 9
|
||||
#endif
|
||||
} _Unwind_Reason_Code;
|
||||
@ -51,12 +56,13 @@ typedef enum {
|
||||
|
||||
typedef struct _Unwind_Context _Unwind_Context; // opaque
|
||||
|
||||
#if _LIBUNWIND_ARM_EHABI
|
||||
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||
typedef uint32_t _Unwind_State;
|
||||
|
||||
static const _Unwind_State _US_VIRTUAL_UNWIND_FRAME = 0;
|
||||
static const _Unwind_State _US_UNWIND_FRAME_STARTING = 1;
|
||||
static const _Unwind_State _US_UNWIND_FRAME_RESUME = 2;
|
||||
static const _Unwind_State _US_ACTION_MASK = 3;
|
||||
/* Undocumented flag for force unwinding. */
|
||||
static const _Unwind_State _US_FORCE_UNWIND = 8;
|
||||
|
||||
@ -99,7 +105,7 @@ struct _Unwind_Control_Block {
|
||||
} pr_cache;
|
||||
|
||||
long long int :0; /* Enforce the 8-byte alignment */
|
||||
};
|
||||
} __attribute__((__aligned__(8)));
|
||||
|
||||
typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
|
||||
(_Unwind_State state,
|
||||
@ -119,15 +125,22 @@ struct _Unwind_Exception {
|
||||
uint64_t exception_class;
|
||||
void (*exception_cleanup)(_Unwind_Reason_Code reason,
|
||||
_Unwind_Exception *exc);
|
||||
#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
|
||||
uintptr_t private_[6];
|
||||
#else
|
||||
uintptr_t private_1; // non-zero means forced unwind
|
||||
uintptr_t private_2; // holds sp that phase1 found for phase2 to use
|
||||
#ifndef __LP64__
|
||||
// The gcc implementation of _Unwind_Exception used attribute mode on the
|
||||
// above fields which had the side effect of causing this whole struct to
|
||||
// round up to 32 bytes in size. To be more explicit, we add pad fields
|
||||
// added for binary compatibility.
|
||||
#endif
|
||||
#if __SIZEOF_POINTER__ == 4
|
||||
// The implementation of _Unwind_Exception uses an attribute mode on the
|
||||
// above fields which has the side effect of causing this whole struct to
|
||||
// round up to 32 bytes in size (48 with SEH). To be more explicit, we add
|
||||
// pad fields added for binary compatibility.
|
||||
uint32_t reserved[3];
|
||||
#endif
|
||||
// The Itanium ABI requires that _Unwind_Exception objects are "double-word
|
||||
// aligned". GCC has interpreted this to mean "use the maximum useful
|
||||
// alignment for the target"; so do we.
|
||||
} __attribute__((__aligned__));
|
||||
|
||||
typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
|
||||
@ -164,7 +177,7 @@ extern void _Unwind_Resume(_Unwind_Exception *exception_object);
|
||||
#endif
|
||||
extern void _Unwind_DeleteException(_Unwind_Exception *exception_object);
|
||||
|
||||
#if _LIBUNWIND_ARM_EHABI
|
||||
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||
typedef enum {
|
||||
_UVRSC_CORE = 0, /* integer register */
|
||||
_UVRSC_VFP = 1, /* vfp */
|
||||
@ -204,7 +217,7 @@ _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
|
||||
_Unwind_VRS_DataRepresentation representation);
|
||||
#endif
|
||||
|
||||
#if !_LIBUNWIND_ARM_EHABI
|
||||
#if !defined(_LIBUNWIND_ARM_EHABI)
|
||||
|
||||
extern uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index);
|
||||
extern void _Unwind_SetGR(struct _Unwind_Context *context, int index,
|
||||
@ -212,7 +225,7 @@ extern void _Unwind_SetGR(struct _Unwind_Context *context, int index,
|
||||
extern uintptr_t _Unwind_GetIP(struct _Unwind_Context *context);
|
||||
extern void _Unwind_SetIP(struct _Unwind_Context *, uintptr_t new_value);
|
||||
|
||||
#else // _LIBUNWIND_ARM_EHABI
|
||||
#else // defined(_LIBUNWIND_ARM_EHABI)
|
||||
|
||||
#if defined(_LIBUNWIND_UNWIND_LEVEL1_EXTERNAL_LINKAGE)
|
||||
#define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 extern
|
||||
@ -251,7 +264,7 @@ void _Unwind_SetIP(struct _Unwind_Context *context, uintptr_t value) {
|
||||
uintptr_t thumb_bit = _Unwind_GetGR(context, 15) & ((uintptr_t)0x1);
|
||||
_Unwind_SetGR(context, 15, value | thumb_bit);
|
||||
}
|
||||
#endif // _LIBUNWIND_ARM_EHABI
|
||||
#endif // defined(_LIBUNWIND_ARM_EHABI)
|
||||
|
||||
extern uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context *context);
|
||||
extern uintptr_t
|
||||
@ -321,7 +334,7 @@ extern void __deregister_frame(const void *fde);
|
||||
|
||||
// _Unwind_Find_FDE() will locate the FDE if the pc is in some function that has
|
||||
// an associated FDE. Note, Mac OS X 10.6 and later, introduces "compact unwind
|
||||
// info" which the runtime uses in preference to dwarf unwind info. This
|
||||
// info" which the runtime uses in preference to DWARF unwind info. This
|
||||
// function will only work if the target function has an FDE but no compact
|
||||
// unwind info.
|
||||
struct dwarf_eh_bases {
|
||||
@ -334,7 +347,7 @@ extern const void *_Unwind_Find_FDE(const void *pc, struct dwarf_eh_bases *);
|
||||
|
||||
// This function attempts to find the start (address of first instruction) of
|
||||
// a function given an address inside the function. It only works if the
|
||||
// function has an FDE (dwarf unwind info).
|
||||
// function has an FDE (DWARF unwind info).
|
||||
// This function is unimplemented on Mac OS X 10.6 and later. Instead, use
|
||||
// _Unwind_Find_FDE() and look at the dwarf_eh_bases.func result.
|
||||
extern void *_Unwind_FindEnclosingFunction(void *pc);
|
||||
@ -365,6 +378,22 @@ extern void *__deregister_frame_info(const void *fde)
|
||||
extern void *__deregister_frame_info_bases(const void *fde)
|
||||
LIBUNWIND_UNAVAIL;
|
||||
|
||||
#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
|
||||
#ifndef _WIN32
|
||||
typedef struct _EXCEPTION_RECORD EXCEPTION_RECORD;
|
||||
typedef struct _CONTEXT CONTEXT;
|
||||
typedef struct _DISPATCHER_CONTEXT DISPATCHER_CONTEXT;
|
||||
#elif !defined(__MINGW32__) && VER_PRODUCTBUILD < 8000
|
||||
typedef struct _DISPATCHER_CONTEXT DISPATCHER_CONTEXT;
|
||||
#endif
|
||||
// This is the common wrapper for GCC-style personality functions with SEH.
|
||||
extern EXCEPTION_DISPOSITION _GCC_specific_handler(EXCEPTION_RECORD *exc,
|
||||
void *frame,
|
||||
CONTEXT *ctx,
|
||||
DISPATCHER_CONTEXT *disp,
|
||||
__personality_routine pers);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -18,7 +18,15 @@
|
||||
#include <stdlib.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>
|
||||
#endif
|
||||
|
||||
@ -32,73 +40,137 @@ namespace libunwind {
|
||||
#include "libunwind.h"
|
||||
#include "config.h"
|
||||
#include "dwarf2.h"
|
||||
#include "EHHeaderParser.hpp"
|
||||
#include "Registers.hpp"
|
||||
|
||||
#if _LIBUNWIND_ARM_EHABI
|
||||
#if defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
#ifdef __APPLE__
|
||||
|
||||
#include <sys/link_elf.h>
|
||||
typedef void *_Unwind_Ptr;
|
||||
struct dyld_unwind_sections
|
||||
{
|
||||
const struct mach_header* mh;
|
||||
const void* dwarf_section;
|
||||
uintptr_t dwarf_section_length;
|
||||
const void* compact_unwind_section;
|
||||
uintptr_t compact_unwind_section_length;
|
||||
};
|
||||
#if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \
|
||||
&& (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) \
|
||||
|| defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
|
||||
// In 10.7.0 or later, libSystem.dylib implements this function.
|
||||
extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *);
|
||||
#else
|
||||
// In 10.6.x and earlier, we need to implement this functionality. Note
|
||||
// that this requires a newer version of libmacho (from cctools) than is
|
||||
// present in libSystem on 10.6.x (for getsectiondata).
|
||||
static inline bool _dyld_find_unwind_sections(void* addr,
|
||||
dyld_unwind_sections* info) {
|
||||
// Find mach-o image containing address.
|
||||
Dl_info dlinfo;
|
||||
if (!dladdr(addr, &dlinfo))
|
||||
return false;
|
||||
#if __LP64__
|
||||
const struct mach_header_64 *mh = (const struct mach_header_64 *)dlinfo.dli_fbase;
|
||||
#else
|
||||
const struct mach_header *mh = (const struct mach_header *)dlinfo.dli_fbase;
|
||||
#endif
|
||||
|
||||
#elif defined(__linux__)
|
||||
// Initialize the return struct
|
||||
info->mh = (const struct mach_header *)mh;
|
||||
info->dwarf_section = getsectiondata(mh, "__TEXT", "__eh_frame", &info->dwarf_section_length);
|
||||
info->compact_unwind_section = getsectiondata(mh, "__TEXT", "__unwind_info", &info->compact_unwind_section_length);
|
||||
|
||||
typedef long unsigned int *_Unwind_Ptr;
|
||||
extern "C" _Unwind_Ptr __gnu_Unwind_Find_exidx(_Unwind_Ptr addr, int *len);
|
||||
if (!info->dwarf_section) {
|
||||
info->dwarf_section_length = 0;
|
||||
}
|
||||
|
||||
// Emulate the BSD dl_unwind_find_exidx API when on a GNU libdl system.
|
||||
#define dl_unwind_find_exidx __gnu_Unwind_Find_exidx
|
||||
if (!info->compact_unwind_section) {
|
||||
info->compact_unwind_section_length = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
|
||||
|
||||
#elif !defined(_LIBUNWIND_IS_BAREMETAL)
|
||||
#include <link.h>
|
||||
#else // !defined(_LIBUNWIND_IS_BAREMETAL)
|
||||
// When statically linked on bare-metal, the symbols for the EH table are looked
|
||||
// up without going through the dynamic loader.
|
||||
struct EHTEntry {
|
||||
uint32_t functionOffset;
|
||||
uint32_t unwindOpcodes;
|
||||
};
|
||||
extern EHTEntry __exidx_start;
|
||||
extern EHTEntry __exidx_end;
|
||||
#endif // !defined(_LIBUNWIND_IS_BAREMETAL)
|
||||
#endif // _LIBUNWIND_ARM_EHABI
|
||||
|
||||
#if defined(__CloudABI__) || defined(__FreeBSD__) || defined(__linux__) || \
|
||||
defined(__NetBSD__)
|
||||
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND && _LIBUNWIND_SUPPORT_DWARF_INDEX
|
||||
// The following linker script may be used to produce the necessary sections and symbols.
|
||||
// Unless the --eh-frame-hdr linker option is provided, the section is not generated
|
||||
// and does not take space in the output file.
|
||||
//
|
||||
// .eh_frame :
|
||||
// {
|
||||
// __eh_frame_start = .;
|
||||
// KEEP(*(.eh_frame))
|
||||
// __eh_frame_end = .;
|
||||
// }
|
||||
//
|
||||
// .eh_frame_hdr :
|
||||
// {
|
||||
// KEEP(*(.eh_frame_hdr))
|
||||
// }
|
||||
//
|
||||
// __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0;
|
||||
// __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0;
|
||||
|
||||
extern char __eh_frame_start;
|
||||
extern char __eh_frame_end;
|
||||
|
||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
|
||||
extern char __eh_frame_hdr_start;
|
||||
extern char __eh_frame_hdr_end;
|
||||
#endif
|
||||
|
||||
#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
|
||||
|
||||
// When statically linked on bare-metal, the symbols for the EH table are looked
|
||||
// up without going through the dynamic loader.
|
||||
extern char __exidx_start;
|
||||
extern char __exidx_end;
|
||||
|
||||
#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||
|
||||
// ELF-based systems may use dl_iterate_phdr() to access sections
|
||||
// containing unwinding information. The ElfW() macro for pointer-size
|
||||
// independent ELF header traversal is not provided by <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>
|
||||
// Macro for machine-independent access to the ELF program headers. This
|
||||
// macro is not available on some systems (e.g., FreeBSD). On these
|
||||
// systems the data structures are just called Elf_XXX. Define ElfW()
|
||||
// locally.
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <psapi.h>
|
||||
#endif
|
||||
#if !defined(ElfW)
|
||||
#define ElfW(type) Elf_##type
|
||||
#endif
|
||||
#include "EHHeaderParser.hpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
namespace libunwind {
|
||||
|
||||
/// Used by findUnwindSections() to return info about needed sections.
|
||||
struct UnwindInfoSections {
|
||||
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND || _LIBUNWIND_SUPPORT_DWARF_INDEX || \
|
||||
_LIBUNWIND_SUPPORT_COMPACT_UNWIND
|
||||
// No dso_base for ARM EHABI.
|
||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) || \
|
||||
defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
|
||||
// No dso_base for SEH or ARM EHABI.
|
||||
uintptr_t dso_base;
|
||||
#endif
|
||||
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
|
||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||
uintptr_t dwarf_section;
|
||||
uintptr_t dwarf_section_length;
|
||||
#endif
|
||||
#if _LIBUNWIND_SUPPORT_DWARF_INDEX
|
||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
|
||||
uintptr_t dwarf_index_section;
|
||||
uintptr_t dwarf_index_section_length;
|
||||
#endif
|
||||
#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND
|
||||
#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
|
||||
uintptr_t compact_unwind_section;
|
||||
uintptr_t compact_unwind_section_length;
|
||||
#endif
|
||||
#if _LIBUNWIND_ARM_EHABI
|
||||
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||
uintptr_t arm_section;
|
||||
uintptr_t arm_section_length;
|
||||
#endif
|
||||
@ -108,15 +180,10 @@ struct UnwindInfoSections {
|
||||
/// LocalAddressSpace is used as a template parameter to UnwindCursor when
|
||||
/// unwinding a thread in the same process. The wrappers compile away,
|
||||
/// making local unwinds fast.
|
||||
class __attribute__((visibility("hidden"))) LocalAddressSpace {
|
||||
class _LIBUNWIND_HIDDEN LocalAddressSpace {
|
||||
public:
|
||||
#ifdef __LP64__
|
||||
typedef uint64_t pint_t;
|
||||
typedef int64_t sint_t;
|
||||
#else
|
||||
typedef uint32_t pint_t;
|
||||
typedef int32_t sint_t;
|
||||
#endif
|
||||
typedef uintptr_t pint_t;
|
||||
typedef intptr_t sint_t;
|
||||
uint8_t get8(pint_t addr) {
|
||||
uint8_t val;
|
||||
memcpy(&val, (void *)addr, sizeof(val));
|
||||
@ -163,7 +230,7 @@ class __attribute__((visibility("hidden"))) LocalAddressSpace {
|
||||
};
|
||||
|
||||
inline uintptr_t LocalAddressSpace::getP(pint_t addr) {
|
||||
#ifdef __LP64__
|
||||
#if __SIZEOF_POINTER__ == 8
|
||||
return get64(addr);
|
||||
#else
|
||||
return get32(addr);
|
||||
@ -171,7 +238,7 @@ inline uintptr_t LocalAddressSpace::getP(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);
|
||||
#else
|
||||
return get32(addr);
|
||||
@ -219,7 +286,7 @@ inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
|
||||
} while (byte & 0x80);
|
||||
// sign extend negative numbers
|
||||
if ((byte & 0x40) != 0)
|
||||
result |= (-1LL) << bit;
|
||||
result |= (-1ULL) << bit;
|
||||
addr = (pint_t) p;
|
||||
return result;
|
||||
}
|
||||
@ -316,55 +383,13 @@ LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
struct dyld_unwind_sections
|
||||
{
|
||||
const struct mach_header* mh;
|
||||
const void* dwarf_section;
|
||||
uintptr_t dwarf_section_length;
|
||||
const void* compact_unwind_section;
|
||||
uintptr_t compact_unwind_section_length;
|
||||
};
|
||||
#if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \
|
||||
&& (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) \
|
||||
|| defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
|
||||
// In 10.7.0 or later, libSystem.dylib implements this function.
|
||||
extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *);
|
||||
#else
|
||||
// In 10.6.x and earlier, we need to implement this functionality.
|
||||
static inline bool _dyld_find_unwind_sections(void* addr,
|
||||
dyld_unwind_sections* info) {
|
||||
// Find mach-o image containing address.
|
||||
Dl_info dlinfo;
|
||||
if (!dladdr(addr, &dlinfo))
|
||||
return false;
|
||||
const mach_header *mh = (const mach_header *)dlinfo.dli_saddr;
|
||||
|
||||
// Find dwarf unwind section in that image.
|
||||
unsigned long size;
|
||||
const uint8_t *p = getsectiondata(mh, "__TEXT", "__eh_frame", &size);
|
||||
if (!p)
|
||||
return false;
|
||||
|
||||
// Fill in return struct.
|
||||
info->mh = mh;
|
||||
info->dwarf_section = p;
|
||||
info->dwarf_section_length = size;
|
||||
info->compact_unwind_section = 0;
|
||||
info->compact_unwind_section_length = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
|
||||
UnwindInfoSections &info) {
|
||||
#ifdef __APPLE__
|
||||
dyld_unwind_sections dyldInfo;
|
||||
if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
|
||||
info.dso_base = (uintptr_t)dyldInfo.mh;
|
||||
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
|
||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||
info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section;
|
||||
info.dwarf_section_length = dyldInfo.dwarf_section_length;
|
||||
#endif
|
||||
@ -372,23 +397,76 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
|
||||
info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
|
||||
return true;
|
||||
}
|
||||
#elif _LIBUNWIND_ARM_EHABI
|
||||
#ifdef _LIBUNWIND_IS_BAREMETAL
|
||||
#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
|
||||
// Bare metal is statically linked, so no need to ask the dynamic loader
|
||||
info.dwarf_section_length = (uintptr_t)(&__eh_frame_end - &__eh_frame_start);
|
||||
info.dwarf_section = (uintptr_t)(&__eh_frame_start);
|
||||
_LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
|
||||
(void *)info.dwarf_section, (void *)info.dwarf_section_length);
|
||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
|
||||
info.dwarf_index_section = (uintptr_t)(&__eh_frame_hdr_start);
|
||||
info.dwarf_index_section_length = (uintptr_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start);
|
||||
_LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p",
|
||||
(void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length);
|
||||
#endif
|
||||
if (info.dwarf_section_length)
|
||||
return true;
|
||||
#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
|
||||
// Bare metal is statically linked, so no need to ask the dynamic loader
|
||||
info.arm_section = (uintptr_t)(&__exidx_start);
|
||||
info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start);
|
||||
#else
|
||||
int length = 0;
|
||||
info.arm_section = (uintptr_t) dl_unwind_find_exidx(
|
||||
(_Unwind_Ptr) targetAddr, &length);
|
||||
info.arm_section_length = (uintptr_t)length;
|
||||
#endif
|
||||
_LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %X length %x",
|
||||
info.arm_section, info.arm_section_length);
|
||||
_LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
|
||||
(void *)info.arm_section, (void *)info.arm_section_length);
|
||||
if (info.arm_section && info.arm_section_length)
|
||||
return true;
|
||||
#elif _LIBUNWIND_SUPPORT_DWARF_UNWIND
|
||||
#if _LIBUNWIND_SUPPORT_DWARF_INDEX
|
||||
#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
|
||||
HMODULE mods[1024];
|
||||
HANDLE process = GetCurrentProcess();
|
||||
DWORD needed;
|
||||
|
||||
if (!EnumProcessModules(process, mods, sizeof(mods), &needed))
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) {
|
||||
PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i];
|
||||
PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew);
|
||||
PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader;
|
||||
PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh);
|
||||
bool found_obj = false;
|
||||
bool found_hdr = false;
|
||||
|
||||
info.dso_base = (uintptr_t)mods[i];
|
||||
for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) {
|
||||
uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i];
|
||||
uintptr_t end = begin + pish->Misc.VirtualSize;
|
||||
if (!strncmp((const char *)pish->Name, ".text",
|
||||
IMAGE_SIZEOF_SHORT_NAME)) {
|
||||
if (targetAddr >= begin && targetAddr < end)
|
||||
found_obj = true;
|
||||
} else if (!strncmp((const char *)pish->Name, ".eh_frame",
|
||||
IMAGE_SIZEOF_SHORT_NAME)) {
|
||||
info.dwarf_section = begin;
|
||||
info.dwarf_section_length = pish->Misc.VirtualSize;
|
||||
found_hdr = true;
|
||||
}
|
||||
if (found_obj && found_hdr)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
#elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
|
||||
// Don't even bother, since Windows has functions that do all this stuff
|
||||
// for us.
|
||||
return true;
|
||||
#elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__) && \
|
||||
(__ANDROID_API__ < 21)
|
||||
int length = 0;
|
||||
info.arm_section =
|
||||
(uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length);
|
||||
info.arm_section_length = (uintptr_t)length;
|
||||
if (info.arm_section && info.arm_section_length)
|
||||
return true;
|
||||
#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||
struct dl_iterate_cb_data {
|
||||
LocalAddressSpace *addressSpace;
|
||||
UnwindInfoSections *sects;
|
||||
@ -399,7 +477,6 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
|
||||
int found = dl_iterate_phdr(
|
||||
[](struct dl_phdr_info *pinfo, size_t, void *data) -> int {
|
||||
auto cbdata = static_cast<dl_iterate_cb_data *>(data);
|
||||
size_t object_length;
|
||||
bool found_obj = false;
|
||||
bool found_hdr = false;
|
||||
|
||||
@ -416,11 +493,32 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
|
||||
#if !defined(Elf_Phdr)
|
||||
typedef ElfW(Phdr) Elf_Phdr;
|
||||
#endif
|
||||
#if !defined(Elf_Addr) && defined(__ANDROID__)
|
||||
typedef ElfW(Addr) Elf_Addr;
|
||||
#endif
|
||||
|
||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||
#if !defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
|
||||
#error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform."
|
||||
#endif
|
||||
size_t object_length;
|
||||
#if defined(__ANDROID__)
|
||||
Elf_Addr image_base =
|
||||
pinfo->dlpi_phnum
|
||||
? reinterpret_cast<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++) {
|
||||
const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
|
||||
if (phdr->p_type == PT_LOAD) {
|
||||
uintptr_t begin = pinfo->dlpi_addr + phdr->p_vaddr;
|
||||
#if defined(__ANDROID__)
|
||||
if (pinfo->dlpi_addr == 0 && phdr->p_vaddr < image_base)
|
||||
begin = begin + image_base;
|
||||
#endif
|
||||
uintptr_t end = begin + phdr->p_memsz;
|
||||
if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
|
||||
cbdata->sects->dso_base = begin;
|
||||
@ -430,6 +528,10 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
|
||||
} else if (phdr->p_type == PT_GNU_EH_FRAME) {
|
||||
EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
|
||||
uintptr_t eh_frame_hdr_start = pinfo->dlpi_addr + phdr->p_vaddr;
|
||||
#if defined(__ANDROID__)
|
||||
if (pinfo->dlpi_addr == 0 && phdr->p_vaddr < image_base)
|
||||
eh_frame_hdr_start = eh_frame_hdr_start + image_base;
|
||||
#endif
|
||||
cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
|
||||
cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
|
||||
EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
|
||||
@ -446,12 +548,26 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
#else // defined(_LIBUNWIND_ARM_EHABI)
|
||||
for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
|
||||
const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
|
||||
if (phdr->p_type == PT_LOAD) {
|
||||
uintptr_t begin = pinfo->dlpi_addr + phdr->p_vaddr;
|
||||
uintptr_t end = begin + phdr->p_memsz;
|
||||
if (cbdata->targetAddr >= begin && cbdata->targetAddr < end)
|
||||
found_obj = true;
|
||||
} else if (phdr->p_type == PT_ARM_EXIDX) {
|
||||
uintptr_t exidx_start = pinfo->dlpi_addr + phdr->p_vaddr;
|
||||
cbdata->sects->arm_section = exidx_start;
|
||||
cbdata->sects->arm_section_length = phdr->p_memsz;
|
||||
found_hdr = true;
|
||||
}
|
||||
}
|
||||
return found_obj && found_hdr;
|
||||
#endif
|
||||
},
|
||||
&cb_data);
|
||||
return static_cast<bool>(found);
|
||||
#else
|
||||
#error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform."
|
||||
#endif
|
||||
#endif
|
||||
|
||||
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,
|
||||
size_t bufLen,
|
||||
unw_word_t *offset) {
|
||||
#ifndef _LIBUNWIND_IS_BAREMETAL
|
||||
#if _LIBUNWIND_USE_DLADDR
|
||||
Dl_info dyldInfo;
|
||||
if (dladdr((void *)addr, &dyldInfo)) {
|
||||
if (dyldInfo.dli_sname != NULL) {
|
||||
@ -489,14 +605,14 @@ inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
|
||||
|
||||
#ifdef UNW_REMOTE
|
||||
|
||||
/// OtherAddressSpace is used as a template parameter to UnwindCursor when
|
||||
/// RemoteAddressSpace is used as a template parameter to UnwindCursor when
|
||||
/// unwinding a thread in the another process. The other process can be a
|
||||
/// different endianness and a different pointer size which is handled by
|
||||
/// the P template parameter.
|
||||
template <typename P>
|
||||
class OtherAddressSpace {
|
||||
class RemoteAddressSpace {
|
||||
public:
|
||||
OtherAddressSpace(task_t task) : fTask(task) {}
|
||||
RemoteAddressSpace(task_t task) : fTask(task) {}
|
||||
|
||||
typedef typename P::uint_t pint_t;
|
||||
|
||||
@ -520,24 +636,24 @@ class OtherAddressSpace {
|
||||
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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
@ -557,7 +673,7 @@ uint64_t OtherAddressSpace<P>::getULEB128(pint_t &addr, pint_t end) {
|
||||
}
|
||||
|
||||
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);
|
||||
LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr);
|
||||
LocalAddressSpace::pint_t sladdr = laddr;
|
||||
@ -566,13 +682,14 @@ int64_t OtherAddressSpace<P>::getSLEB128(pint_t &addr, pint_t end) {
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename P> void *OtherAddressSpace<P>::localCopy(pint_t addr) {
|
||||
template <typename P> void *RemoteAddressSpace<P>::localCopy(pint_t addr) {
|
||||
// FIX ME
|
||||
}
|
||||
|
||||
template <typename P>
|
||||
bool OtherAddressSpace<P>::findFunctionName(pint_t addr, char *buf,
|
||||
size_t bufLen, unw_word_t *offset) {
|
||||
bool RemoteAddressSpace<P>::findFunctionName(pint_t addr, char *buf,
|
||||
size_t bufLen,
|
||||
unw_word_t *offset) {
|
||||
// FIX ME
|
||||
}
|
||||
|
||||
@ -588,7 +705,7 @@ struct unw_addr_space {
|
||||
/// a 32-bit intel process.
|
||||
struct unw_addr_space_i386 : public unw_addr_space {
|
||||
unw_addr_space_i386(task_t task) : oas(task) {}
|
||||
OtherAddressSpace<Pointer32<LittleEndian> > oas;
|
||||
RemoteAddressSpace<Pointer32<LittleEndian>> oas;
|
||||
};
|
||||
|
||||
/// 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.
|
||||
struct unw_addr_space_x86_64 : public unw_addr_space {
|
||||
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
|
||||
@ -604,7 +721,14 @@ struct unw_addr_space_x86_64 : public unw_addr_space {
|
||||
/// a 32-bit PowerPC process.
|
||||
struct unw_addr_space_ppc : public unw_addr_space {
|
||||
unw_addr_space_ppc(task_t task) : oas(task) {}
|
||||
OtherAddressSpace<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
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include <libunwind.h>
|
||||
#include <mach-o/compact_unwind_encoding.h>
|
||||
|
||||
#include "AddressSpace.hpp"
|
||||
#include "Registers.hpp"
|
||||
|
||||
#define EXTRACT_BITS(value, mask) \
|
||||
|
@ -6,7 +6,7 @@
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//
|
||||
// Processor specific interpretation of dwarf unwind info.
|
||||
// Processor specific interpretation of DWARF unwind info.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@ -18,7 +18,6 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "dwarf2.h"
|
||||
#include "AddressSpace.hpp"
|
||||
#include "Registers.hpp"
|
||||
#include "DwarfParser.hpp"
|
||||
#include "config.h"
|
||||
@ -27,7 +26,7 @@
|
||||
namespace libunwind {
|
||||
|
||||
|
||||
/// DwarfInstructions maps abtract dwarf unwind instructions to a particular
|
||||
/// DwarfInstructions maps abtract DWARF unwind instructions to a particular
|
||||
/// architecture
|
||||
template <typename A, typename R>
|
||||
class DwarfInstructions {
|
||||
@ -160,15 +159,15 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
|
||||
&cieInfo) == NULL) {
|
||||
PrologInfo prolog;
|
||||
if (CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc,
|
||||
&prolog)) {
|
||||
R::getArch(), &prolog)) {
|
||||
// get pointer to cfa (architecture specific)
|
||||
pint_t cfa = getCFA(addressSpace, prolog, registers);
|
||||
|
||||
// restore registers that dwarf says were saved
|
||||
// restore registers that DWARF says were saved
|
||||
R newRegisters = registers;
|
||||
pint_t returnAddress = 0;
|
||||
const int lastReg = R::lastDwarfRegNum();
|
||||
assert((int)CFI_Parser<A>::kMaxRegisterNumber > lastReg &&
|
||||
assert(static_cast<int>(CFI_Parser<A>::kMaxRegisterNumber) >= lastReg &&
|
||||
"register range too large");
|
||||
assert(lastReg >= (int)cieInfo.returnAddressRegister &&
|
||||
"register range does not contain return address register");
|
||||
@ -199,6 +198,42 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
|
||||
// restoring SP means setting it to CFA.
|
||||
newRegisters.setSP(cfa);
|
||||
|
||||
#if defined(_LIBUNWIND_TARGET_AARCH64)
|
||||
// If the target is aarch64 then the return address may have been signed
|
||||
// using the v8.3 pointer authentication extensions. The original
|
||||
// return address needs to be authenticated before the return address is
|
||||
// restored. autia1716 is used instead of autia as autia1716 assembles
|
||||
// to a NOP on pre-v8.3a architectures.
|
||||
if ((R::getArch() == REGISTERS_ARM64) &&
|
||||
prolog.savedRegisters[UNW_ARM64_RA_SIGN_STATE].value) {
|
||||
#if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
|
||||
return UNW_ECROSSRASIGNING;
|
||||
#else
|
||||
register unsigned long long x17 __asm("x17") = returnAddress;
|
||||
register unsigned long long x16 __asm("x16") = cfa;
|
||||
|
||||
// These are the autia1716/autib1716 instructions. The hint instructions
|
||||
// are used here as gcc does not assemble autia1716/autib1716 for pre
|
||||
// armv8.3a targets.
|
||||
if (cieInfo.addressesSignedWithBKey)
|
||||
asm("hint 0xe" : "+r"(x17) : "r"(x16)); // autib1716
|
||||
else
|
||||
asm("hint 0xc" : "+r"(x17) : "r"(x16)); // autia1716
|
||||
returnAddress = x17;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_LIBUNWIND_TARGET_SPARC)
|
||||
if (R::getArch() == REGISTERS_SPARC) {
|
||||
// Skip call site instruction and delay slot
|
||||
returnAddress += 8;
|
||||
// Skip unimp instruction if function returns a struct
|
||||
if ((addressSpace.get32(returnAddress) & 0xC1C00000) == 0)
|
||||
returnAddress += 4;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Return address is address after call site instruction, so setting IP to
|
||||
// that does simualates a return.
|
||||
newRegisters.setIP(returnAddress);
|
||||
@ -480,7 +515,7 @@ DwarfInstructions<A, R>::evaluateExpression(pint_t expression, A &addressSpace,
|
||||
|
||||
case DW_OP_plus_uconst:
|
||||
// pop stack, add uelb128 constant, push result
|
||||
*sp += addressSpace.getULEB128(p, expressionEnd);
|
||||
*sp += static_cast<pint_t>(addressSpace.getULEB128(p, expressionEnd));
|
||||
if (log)
|
||||
fprintf(stderr, "add constant\n");
|
||||
break;
|
||||
@ -744,7 +779,7 @@ DwarfInstructions<A, R>::evaluateExpression(pint_t expression, A &addressSpace,
|
||||
case DW_OP_call4:
|
||||
case DW_OP_call_ref:
|
||||
default:
|
||||
_LIBUNWIND_ABORT("dwarf opcode not implemented");
|
||||
_LIBUNWIND_ABORT("DWARF opcode not implemented");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,13 +20,14 @@
|
||||
|
||||
#include "libunwind.h"
|
||||
#include "dwarf2.h"
|
||||
#include "Registers.hpp"
|
||||
|
||||
#include "AddressSpace.hpp"
|
||||
#include "config.h"
|
||||
|
||||
namespace libunwind {
|
||||
|
||||
/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
|
||||
/// See Dwarf Spec for details:
|
||||
/// See DWARF Spec for details:
|
||||
/// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
|
||||
///
|
||||
template <typename A>
|
||||
@ -49,6 +50,9 @@ class CFI_Parser {
|
||||
bool isSignalFrame;
|
||||
bool fdesHaveAugmentationData;
|
||||
uint8_t returnAddressRegister;
|
||||
#if defined(_LIBUNWIND_TARGET_AARCH64)
|
||||
bool addressesSignedWithBKey;
|
||||
#endif
|
||||
};
|
||||
|
||||
/// Information about an FDE (Frame Description Entry)
|
||||
@ -62,7 +66,7 @@ class CFI_Parser {
|
||||
};
|
||||
|
||||
enum {
|
||||
kMaxRegisterNumber = _LIBUNWIND_MAX_REGISTER
|
||||
kMaxRegisterNumber = _LIBUNWIND_HIGHEST_DWARF_REGISTER
|
||||
};
|
||||
enum RegisterSavedWhere {
|
||||
kRegisterUnused,
|
||||
@ -77,7 +81,7 @@ class CFI_Parser {
|
||||
int64_t value;
|
||||
};
|
||||
/// Information about a frame layout and registers saved determined
|
||||
/// by "running" the dwarf FDE "instructions"
|
||||
/// by "running" the DWARF FDE "instructions"
|
||||
struct PrologInfo {
|
||||
uint32_t cfaRegister;
|
||||
int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
|
||||
@ -86,7 +90,7 @@ class CFI_Parser {
|
||||
uint32_t codeOffsetAtStackDecrement;
|
||||
bool registersInOtherRegisters;
|
||||
bool sameValueUsed;
|
||||
RegisterLocation savedRegisters[kMaxRegisterNumber];
|
||||
RegisterLocation savedRegisters[kMaxRegisterNumber + 1];
|
||||
};
|
||||
|
||||
struct PrologInfoStackEntry {
|
||||
@ -103,7 +107,7 @@ class CFI_Parser {
|
||||
FDE_Info *fdeInfo, CIE_Info *cieInfo);
|
||||
static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
|
||||
const CIE_Info &cieInfo, pint_t upToPC,
|
||||
PrologInfo *results);
|
||||
int arch, PrologInfo *results);
|
||||
|
||||
static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
|
||||
|
||||
@ -111,7 +115,7 @@ class CFI_Parser {
|
||||
static bool parseInstructions(A &addressSpace, pint_t instructions,
|
||||
pint_t instructionsEnd, const CIE_Info &cieInfo,
|
||||
pint_t pcoffset,
|
||||
PrologInfoStackEntry *&rememberStack,
|
||||
PrologInfoStackEntry *&rememberStack, int arch,
|
||||
PrologInfo *results);
|
||||
};
|
||||
|
||||
@ -138,23 +142,23 @@ const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
|
||||
if (err != NULL)
|
||||
return err;
|
||||
p += 4;
|
||||
// parse pc begin and range
|
||||
// Parse pc begin and range.
|
||||
pint_t pcStart =
|
||||
addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
|
||||
pint_t pcRange =
|
||||
addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
|
||||
// parse rest of info
|
||||
// Parse rest of info.
|
||||
fdeInfo->lsda = 0;
|
||||
// check for augmentation length
|
||||
// Check for augmentation length.
|
||||
if (cieInfo->fdesHaveAugmentationData) {
|
||||
pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
|
||||
pint_t endOfAug = p + augLen;
|
||||
if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
|
||||
// peek at value (without indirection). Zero means no lsda
|
||||
// Peek at value (without indirection). Zero means no LSDA.
|
||||
pint_t lsdaStart = p;
|
||||
if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) !=
|
||||
0) {
|
||||
// reset pointer and re-parse lsda address
|
||||
// Reset pointer and re-parse LSDA address.
|
||||
p = lsdaStart;
|
||||
fdeInfo->lsda =
|
||||
addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
|
||||
@ -192,23 +196,23 @@ bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
|
||||
return false; // end marker
|
||||
uint32_t id = addressSpace.get32(p);
|
||||
if (id == 0) {
|
||||
// skip over CIEs
|
||||
// Skip over CIEs.
|
||||
p += cfiLength;
|
||||
} else {
|
||||
// process FDE to see if it covers pc
|
||||
// Process FDE to see if it covers pc.
|
||||
pint_t nextCFI = p + cfiLength;
|
||||
uint32_t ciePointer = addressSpace.get32(p);
|
||||
pint_t cieStart = p - ciePointer;
|
||||
// validate pointer to CIE is within section
|
||||
// Validate pointer to CIE is within section.
|
||||
if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) {
|
||||
if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) {
|
||||
p += 4;
|
||||
// parse pc begin and range
|
||||
// Parse pc begin and range.
|
||||
pint_t pcStart =
|
||||
addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
|
||||
pint_t pcRange = addressSpace.getEncodedP(
|
||||
p, nextCFI, cieInfo->pointerEncoding & 0x0F);
|
||||
// test if pc is within the function this FDE covers
|
||||
// Test if pc is within the function this FDE covers.
|
||||
if ((pcStart < pc) && (pc <= pcStart + pcRange)) {
|
||||
// parse rest of info
|
||||
fdeInfo->lsda = 0;
|
||||
@ -217,11 +221,11 @@ bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
|
||||
pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
|
||||
pint_t endOfAug = p + augLen;
|
||||
if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
|
||||
// peek at value (without indirection). Zero means no lsda
|
||||
// Peek at value (without indirection). Zero means no LSDA.
|
||||
pint_t lsdaStart = p;
|
||||
if (addressSpace.getEncodedP(
|
||||
p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) {
|
||||
// reset pointer and re-parse lsda address
|
||||
// Reset pointer and re-parse LSDA address.
|
||||
p = lsdaStart;
|
||||
fdeInfo->lsda = addressSpace
|
||||
.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
|
||||
@ -239,7 +243,7 @@ bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
|
||||
// pc is not in begin/range, skip this FDE
|
||||
}
|
||||
} else {
|
||||
// malformed CIE, now augmentation describing pc range encoding
|
||||
// Malformed CIE, now augmentation describing pc range encoding.
|
||||
}
|
||||
} else {
|
||||
// malformed FDE. CIE is bad
|
||||
@ -263,6 +267,9 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
|
||||
cieInfo->dataAlignFactor = 0;
|
||||
cieInfo->isSignalFrame = false;
|
||||
cieInfo->fdesHaveAugmentationData = false;
|
||||
#if defined(_LIBUNWIND_TARGET_AARCH64)
|
||||
cieInfo->addressesSignedWithBKey = false;
|
||||
#endif
|
||||
cieInfo->cieStart = cie;
|
||||
pint_t p = cie;
|
||||
pint_t cieLength = (pint_t)addressSpace.get32(p);
|
||||
@ -326,6 +333,11 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
|
||||
case 'S':
|
||||
cieInfo->isSignalFrame = true;
|
||||
break;
|
||||
#if defined(_LIBUNWIND_TARGET_AARCH64)
|
||||
case 'B':
|
||||
cieInfo->addressesSignedWithBKey = true;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
// ignore unknown letters
|
||||
break;
|
||||
@ -338,12 +350,12 @@ const char *CFI_Parser<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>
|
||||
bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
|
||||
const FDE_Info &fdeInfo,
|
||||
const CIE_Info &cieInfo, pint_t upToPC,
|
||||
PrologInfo *results) {
|
||||
int arch, PrologInfo *results) {
|
||||
// clear results
|
||||
memset(results, '\0', sizeof(PrologInfo));
|
||||
PrologInfoStackEntry *rememberStack = NULL;
|
||||
@ -351,28 +363,28 @@ bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
|
||||
// parse CIE then FDE instructions
|
||||
return parseInstructions(addressSpace, cieInfo.cieInstructions,
|
||||
cieInfo.cieStart + cieInfo.cieLength, cieInfo,
|
||||
(pint_t)(-1), rememberStack, results) &&
|
||||
(pint_t)(-1), rememberStack, arch, results) &&
|
||||
parseInstructions(addressSpace, fdeInfo.fdeInstructions,
|
||||
fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo,
|
||||
upToPC - fdeInfo.pcStart, rememberStack, results);
|
||||
upToPC - fdeInfo.pcStart, rememberStack, arch,
|
||||
results);
|
||||
}
|
||||
|
||||
/// "run" the dwarf instructions
|
||||
/// "run" the DWARF instructions
|
||||
template <typename A>
|
||||
bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
|
||||
pint_t instructionsEnd,
|
||||
const CIE_Info &cieInfo, pint_t pcoffset,
|
||||
PrologInfoStackEntry *&rememberStack,
|
||||
PrologInfo *results) {
|
||||
const bool logDwarf = false;
|
||||
int arch, PrologInfo *results) {
|
||||
pint_t p = instructions;
|
||||
pint_t codeOffset = 0;
|
||||
PrologInfo initialState = *results;
|
||||
if (logDwarf)
|
||||
fprintf(stderr, "parseInstructions(instructions=0x%0" PRIx64 ")\n",
|
||||
(uint64_t)instructionsEnd);
|
||||
|
||||
// see Dwarf Spec, section 6.4.2 for details on unwind opcodes
|
||||
_LIBUNWIND_TRACE_DWARF("parseInstructions(instructions=0x%0" PRIx64 ")\n",
|
||||
static_cast<uint64_t>(instructionsEnd));
|
||||
|
||||
// see DWARF Spec, section 6.4.2 for details on unwind opcodes
|
||||
while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
|
||||
uint64_t reg;
|
||||
uint64_t reg2;
|
||||
@ -386,81 +398,71 @@ bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
|
||||
++p;
|
||||
switch (opcode) {
|
||||
case DW_CFA_nop:
|
||||
if (logDwarf)
|
||||
fprintf(stderr, "DW_CFA_nop\n");
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n");
|
||||
break;
|
||||
case DW_CFA_set_loc:
|
||||
codeOffset =
|
||||
addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
|
||||
if (logDwarf)
|
||||
fprintf(stderr, "DW_CFA_set_loc\n");
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n");
|
||||
break;
|
||||
case DW_CFA_advance_loc1:
|
||||
codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
|
||||
p += 1;
|
||||
if (logDwarf)
|
||||
fprintf(stderr, "DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",
|
||||
(uint64_t)codeOffset);
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",
|
||||
static_cast<uint64_t>(codeOffset));
|
||||
break;
|
||||
case DW_CFA_advance_loc2:
|
||||
codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
|
||||
p += 2;
|
||||
if (logDwarf)
|
||||
fprintf(stderr, "DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",
|
||||
(uint64_t)codeOffset);
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",
|
||||
static_cast<uint64_t>(codeOffset));
|
||||
break;
|
||||
case DW_CFA_advance_loc4:
|
||||
codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
|
||||
p += 4;
|
||||
if (logDwarf)
|
||||
fprintf(stderr, "DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",
|
||||
(uint64_t)codeOffset);
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",
|
||||
static_cast<uint64_t>(codeOffset));
|
||||
break;
|
||||
case DW_CFA_offset_extended:
|
||||
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||
offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
|
||||
* cieInfo.dataAlignFactor;
|
||||
if (reg > kMaxRegisterNumber) {
|
||||
fprintf(stderr,
|
||||
"malformed DW_CFA_offset_extended dwarf unwind, reg too big\n");
|
||||
_LIBUNWIND_LOG0(
|
||||
"malformed DW_CFA_offset_extended DWARF unwind, reg too big");
|
||||
return false;
|
||||
}
|
||||
results->savedRegisters[reg].location = kRegisterInCFA;
|
||||
results->savedRegisters[reg].value = offset;
|
||||
if (logDwarf)
|
||||
fprintf(stderr,
|
||||
"DW_CFA_offset_extended(reg=%" PRIu64 ", offset=%" PRId64 ")\n",
|
||||
reg, offset);
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", "
|
||||
"offset=%" PRId64 ")\n",
|
||||
reg, offset);
|
||||
break;
|
||||
case DW_CFA_restore_extended:
|
||||
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||
;
|
||||
if (reg > kMaxRegisterNumber) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"malformed DW_CFA_restore_extended dwarf unwind, reg too big\n");
|
||||
_LIBUNWIND_LOG0(
|
||||
"malformed DW_CFA_restore_extended DWARF unwind, reg too big");
|
||||
return false;
|
||||
}
|
||||
results->savedRegisters[reg] = initialState.savedRegisters[reg];
|
||||
if (logDwarf)
|
||||
fprintf(stderr, "DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg);
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg);
|
||||
break;
|
||||
case DW_CFA_undefined:
|
||||
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||
if (reg > kMaxRegisterNumber) {
|
||||
fprintf(stderr,
|
||||
"malformed DW_CFA_undefined dwarf unwind, reg too big\n");
|
||||
_LIBUNWIND_LOG0(
|
||||
"malformed DW_CFA_undefined DWARF unwind, reg too big");
|
||||
return false;
|
||||
}
|
||||
results->savedRegisters[reg].location = kRegisterUnused;
|
||||
if (logDwarf)
|
||||
fprintf(stderr, "DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
|
||||
break;
|
||||
case DW_CFA_same_value:
|
||||
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||
if (reg > kMaxRegisterNumber) {
|
||||
fprintf(stderr,
|
||||
"malformed DW_CFA_same_value dwarf unwind, reg too big\n");
|
||||
_LIBUNWIND_LOG0(
|
||||
"malformed DW_CFA_same_value DWARF unwind, reg too big");
|
||||
return false;
|
||||
}
|
||||
// <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;
|
||||
// set flag to disable conversion to compact unwind
|
||||
results->sameValueUsed = true;
|
||||
if (logDwarf)
|
||||
fprintf(stderr, "DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);
|
||||
break;
|
||||
case DW_CFA_register:
|
||||
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||
reg2 = addressSpace.getULEB128(p, instructionsEnd);
|
||||
if (reg > kMaxRegisterNumber) {
|
||||
fprintf(stderr,
|
||||
"malformed DW_CFA_register dwarf unwind, reg too big\n");
|
||||
_LIBUNWIND_LOG0(
|
||||
"malformed DW_CFA_register DWARF unwind, reg too big");
|
||||
return false;
|
||||
}
|
||||
if (reg2 > kMaxRegisterNumber) {
|
||||
fprintf(stderr,
|
||||
"malformed DW_CFA_register dwarf unwind, reg2 too big\n");
|
||||
_LIBUNWIND_LOG0(
|
||||
"malformed DW_CFA_register DWARF unwind, reg2 too big");
|
||||
return false;
|
||||
}
|
||||
results->savedRegisters[reg].location = kRegisterInRegister;
|
||||
results->savedRegisters[reg].value = (int64_t)reg2;
|
||||
// set flag to disable conversion to compact unwind
|
||||
results->registersInOtherRegisters = true;
|
||||
if (logDwarf)
|
||||
fprintf(stderr, "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n",
|
||||
reg, reg2);
|
||||
_LIBUNWIND_TRACE_DWARF(
|
||||
"DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2);
|
||||
break;
|
||||
#if !defined(_LIBUNWIND_NO_HEAP)
|
||||
case DW_CFA_remember_state:
|
||||
@ -505,8 +505,7 @@ bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (logDwarf)
|
||||
fprintf(stderr, "DW_CFA_remember_state\n");
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n");
|
||||
break;
|
||||
case DW_CFA_restore_state:
|
||||
if (rememberStack != NULL) {
|
||||
@ -517,202 +516,243 @@ bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (logDwarf)
|
||||
fprintf(stderr, "DW_CFA_restore_state\n");
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n");
|
||||
break;
|
||||
#endif
|
||||
case DW_CFA_def_cfa:
|
||||
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||
offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
|
||||
if (reg > kMaxRegisterNumber) {
|
||||
fprintf(stderr, "malformed DW_CFA_def_cfa dwarf unwind, reg too big\n");
|
||||
_LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big");
|
||||
return false;
|
||||
}
|
||||
results->cfaRegister = (uint32_t)reg;
|
||||
results->cfaRegisterOffset = (int32_t)offset;
|
||||
if (logDwarf)
|
||||
fprintf(stderr, "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n",
|
||||
reg, offset);
|
||||
_LIBUNWIND_TRACE_DWARF(
|
||||
"DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", reg, offset);
|
||||
break;
|
||||
case DW_CFA_def_cfa_register:
|
||||
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||
if (reg > kMaxRegisterNumber) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"malformed DW_CFA_def_cfa_register dwarf unwind, reg too big\n");
|
||||
_LIBUNWIND_LOG0(
|
||||
"malformed DW_CFA_def_cfa_register DWARF unwind, reg too big");
|
||||
return false;
|
||||
}
|
||||
results->cfaRegister = (uint32_t)reg;
|
||||
if (logDwarf)
|
||||
fprintf(stderr, "DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
|
||||
break;
|
||||
case DW_CFA_def_cfa_offset:
|
||||
results->cfaRegisterOffset = (int32_t)
|
||||
addressSpace.getULEB128(p, instructionsEnd);
|
||||
results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
|
||||
if (logDwarf)
|
||||
fprintf(stderr, "DW_CFA_def_cfa_offset(%d)\n",
|
||||
results->cfaRegisterOffset);
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n",
|
||||
results->cfaRegisterOffset);
|
||||
break;
|
||||
case DW_CFA_def_cfa_expression:
|
||||
results->cfaRegister = 0;
|
||||
results->cfaExpression = (int64_t)p;
|
||||
length = addressSpace.getULEB128(p, instructionsEnd);
|
||||
p += length;
|
||||
if (logDwarf)
|
||||
fprintf(stderr, "DW_CFA_def_cfa_expression(expression=0x%" PRIx64
|
||||
", length=%" PRIu64 ")\n",
|
||||
results->cfaExpression, length);
|
||||
assert(length < static_cast<pint_t>(~0) && "pointer overflow");
|
||||
p += static_cast<pint_t>(length);
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64
|
||||
", length=%" PRIu64 ")\n",
|
||||
results->cfaExpression, length);
|
||||
break;
|
||||
case DW_CFA_expression:
|
||||
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||
if (reg > kMaxRegisterNumber) {
|
||||
fprintf(stderr,
|
||||
"malformed DW_CFA_expression dwarf unwind, reg too big\n");
|
||||
_LIBUNWIND_LOG0(
|
||||
"malformed DW_CFA_expression DWARF unwind, reg too big");
|
||||
return false;
|
||||
}
|
||||
results->savedRegisters[reg].location = kRegisterAtExpression;
|
||||
results->savedRegisters[reg].value = (int64_t)p;
|
||||
length = addressSpace.getULEB128(p, instructionsEnd);
|
||||
p += length;
|
||||
if (logDwarf)
|
||||
fprintf(stderr, "DW_CFA_expression(reg=%" PRIu64
|
||||
", expression=0x%" PRIx64 ", length=%" PRIu64 ")\n",
|
||||
reg, results->savedRegisters[reg].value, length);
|
||||
assert(length < static_cast<pint_t>(~0) && "pointer overflow");
|
||||
p += static_cast<pint_t>(length);
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", "
|
||||
"expression=0x%" PRIx64 ", "
|
||||
"length=%" PRIu64 ")\n",
|
||||
reg, results->savedRegisters[reg].value, length);
|
||||
break;
|
||||
case DW_CFA_offset_extended_sf:
|
||||
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||
if (reg > kMaxRegisterNumber) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"malformed DW_CFA_offset_extended_sf dwarf unwind, reg too big\n");
|
||||
_LIBUNWIND_LOG0(
|
||||
"malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big");
|
||||
return false;
|
||||
}
|
||||
offset =
|
||||
addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
|
||||
results->savedRegisters[reg].location = kRegisterInCFA;
|
||||
results->savedRegisters[reg].value = offset;
|
||||
if (logDwarf)
|
||||
fprintf(stderr, "DW_CFA_offset_extended_sf(reg=%" PRIu64
|
||||
", offset=%" PRId64 ")\n",
|
||||
reg, offset);
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", "
|
||||
"offset=%" PRId64 ")\n",
|
||||
reg, offset);
|
||||
break;
|
||||
case DW_CFA_def_cfa_sf:
|
||||
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||
offset =
|
||||
addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
|
||||
if (reg > kMaxRegisterNumber) {
|
||||
fprintf(stderr,
|
||||
"malformed DW_CFA_def_cfa_sf dwarf unwind, reg too big\n");
|
||||
_LIBUNWIND_LOG0(
|
||||
"malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big");
|
||||
return false;
|
||||
}
|
||||
results->cfaRegister = (uint32_t)reg;
|
||||
results->cfaRegisterOffset = (int32_t)offset;
|
||||
if (logDwarf)
|
||||
fprintf(stderr,
|
||||
"DW_CFA_def_cfa_sf(reg=%" PRIu64 ", offset=%" PRId64 ")\n", reg,
|
||||
offset);
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", "
|
||||
"offset=%" PRId64 ")\n",
|
||||
reg, offset);
|
||||
break;
|
||||
case DW_CFA_def_cfa_offset_sf:
|
||||
results->cfaRegisterOffset = (int32_t)
|
||||
(addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor);
|
||||
results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
|
||||
if (logDwarf)
|
||||
fprintf(stderr, "DW_CFA_def_cfa_offset_sf(%d)\n",
|
||||
results->cfaRegisterOffset);
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n",
|
||||
results->cfaRegisterOffset);
|
||||
break;
|
||||
case DW_CFA_val_offset:
|
||||
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||
if (reg > kMaxRegisterNumber) {
|
||||
_LIBUNWIND_LOG(
|
||||
"malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64
|
||||
") out of range\n",
|
||||
reg);
|
||||
return false;
|
||||
}
|
||||
offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
|
||||
* cieInfo.dataAlignFactor;
|
||||
results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
|
||||
results->savedRegisters[reg].value = offset;
|
||||
if (logDwarf)
|
||||
fprintf(stderr,
|
||||
"DW_CFA_val_offset(reg=%" PRIu64 ", offset=%" PRId64 "\n", reg,
|
||||
offset);
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "
|
||||
"offset=%" PRId64 "\n",
|
||||
reg, offset);
|
||||
break;
|
||||
case DW_CFA_val_offset_sf:
|
||||
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||
if (reg > kMaxRegisterNumber) {
|
||||
fprintf(stderr,
|
||||
"malformed DW_CFA_val_offset_sf dwarf unwind, reg too big\n");
|
||||
_LIBUNWIND_LOG0(
|
||||
"malformed DW_CFA_val_offset_sf DWARF unwind, reg too big");
|
||||
return false;
|
||||
}
|
||||
offset =
|
||||
addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
|
||||
results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
|
||||
results->savedRegisters[reg].value = offset;
|
||||
if (logDwarf)
|
||||
fprintf(stderr,
|
||||
"DW_CFA_val_offset_sf(reg=%" PRIu64 ", offset=%" PRId64 "\n",
|
||||
reg, offset);
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "
|
||||
"offset=%" PRId64 "\n",
|
||||
reg, offset);
|
||||
break;
|
||||
case DW_CFA_val_expression:
|
||||
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||
if (reg > kMaxRegisterNumber) {
|
||||
fprintf(stderr,
|
||||
"malformed DW_CFA_val_expression dwarf unwind, reg too big\n");
|
||||
_LIBUNWIND_LOG0(
|
||||
"malformed DW_CFA_val_expression DWARF unwind, reg too big");
|
||||
return false;
|
||||
}
|
||||
results->savedRegisters[reg].location = kRegisterIsExpression;
|
||||
results->savedRegisters[reg].value = (int64_t)p;
|
||||
length = addressSpace.getULEB128(p, instructionsEnd);
|
||||
p += length;
|
||||
if (logDwarf)
|
||||
fprintf(stderr, "DW_CFA_val_expression(reg=%" PRIu64
|
||||
", expression=0x%" PRIx64 ", length=%" PRIu64 ")\n",
|
||||
reg, results->savedRegisters[reg].value, length);
|
||||
assert(length < static_cast<pint_t>(~0) && "pointer overflow");
|
||||
p += static_cast<pint_t>(length);
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "
|
||||
"expression=0x%" PRIx64 ", length=%" PRIu64 ")\n",
|
||||
reg, results->savedRegisters[reg].value, length);
|
||||
break;
|
||||
case DW_CFA_GNU_args_size:
|
||||
length = addressSpace.getULEB128(p, instructionsEnd);
|
||||
results->spExtraArgSize = (uint32_t)length;
|
||||
if (logDwarf)
|
||||
fprintf(stderr, "DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
|
||||
break;
|
||||
case DW_CFA_GNU_negative_offset_extended:
|
||||
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||
if (reg > kMaxRegisterNumber) {
|
||||
fprintf(stderr, "malformed DW_CFA_GNU_negative_offset_extended dwarf "
|
||||
"unwind, reg too big\n");
|
||||
_LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF "
|
||||
"unwind, reg too big");
|
||||
return false;
|
||||
}
|
||||
offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
|
||||
* cieInfo.dataAlignFactor;
|
||||
results->savedRegisters[reg].location = kRegisterInCFA;
|
||||
results->savedRegisters[reg].value = -offset;
|
||||
if (logDwarf)
|
||||
fprintf(stderr, "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n",
|
||||
offset);
|
||||
_LIBUNWIND_TRACE_DWARF(
|
||||
"DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
|
||||
break;
|
||||
|
||||
#if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC)
|
||||
// The same constant is used to represent different instructions on
|
||||
// AArch64 (negate_ra_state) and SPARC (window_save).
|
||||
static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save,
|
||||
"uses the same constant");
|
||||
case DW_CFA_AARCH64_negate_ra_state:
|
||||
switch (arch) {
|
||||
#if defined(_LIBUNWIND_TARGET_AARCH64)
|
||||
case REGISTERS_ARM64:
|
||||
results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^= 0x1;
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n");
|
||||
break;
|
||||
#endif
|
||||
#if defined(_LIBUNWIND_TARGET_SPARC)
|
||||
// case DW_CFA_GNU_window_save:
|
||||
case REGISTERS_SPARC:
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n");
|
||||
for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) {
|
||||
results->savedRegisters[reg].location = kRegisterInRegister;
|
||||
results->savedRegisters[reg].value =
|
||||
((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0;
|
||||
}
|
||||
|
||||
for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {
|
||||
results->savedRegisters[reg].location = kRegisterInCFA;
|
||||
results->savedRegisters[reg].value =
|
||||
((int64_t)reg - UNW_SPARC_L0) * 4;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
#else
|
||||
(void)arch;
|
||||
#endif
|
||||
|
||||
default:
|
||||
operand = opcode & 0x3F;
|
||||
switch (opcode & 0xC0) {
|
||||
case DW_CFA_offset:
|
||||
reg = operand;
|
||||
if (reg > kMaxRegisterNumber) {
|
||||
_LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64
|
||||
") out of range",
|
||||
reg);
|
||||
return false;
|
||||
}
|
||||
offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
|
||||
* cieInfo.dataAlignFactor;
|
||||
results->savedRegisters[reg].location = kRegisterInCFA;
|
||||
results->savedRegisters[reg].value = offset;
|
||||
if (logDwarf)
|
||||
fprintf(stderr, "DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
|
||||
operand, offset);
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
|
||||
operand, offset);
|
||||
break;
|
||||
case DW_CFA_advance_loc:
|
||||
codeOffset += operand * cieInfo.codeAlignFactor;
|
||||
if (logDwarf)
|
||||
fprintf(stderr, "DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
|
||||
(uint64_t)codeOffset);
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
|
||||
static_cast<uint64_t>(codeOffset));
|
||||
break;
|
||||
case DW_CFA_restore:
|
||||
reg = operand;
|
||||
if (reg > kMaxRegisterNumber) {
|
||||
_LIBUNWIND_LOG("malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64
|
||||
") out of range",
|
||||
reg);
|
||||
return false;
|
||||
}
|
||||
results->savedRegisters[reg] = initialState.savedRegisters[reg];
|
||||
if (logDwarf)
|
||||
fprintf(stderr, "DW_CFA_restore(reg=%" PRIu64 ")\n", reg);
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",
|
||||
static_cast<uint64_t>(operand));
|
||||
break;
|
||||
default:
|
||||
if (logDwarf)
|
||||
fprintf(stderr, "unknown CFA opcode 0x%02X\n", opcode);
|
||||
_LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
|
||||
#include "libunwind.h"
|
||||
|
||||
#include "AddressSpace.hpp"
|
||||
#include "DwarfParser.hpp"
|
||||
|
||||
namespace libunwind {
|
||||
@ -68,7 +67,9 @@ void EHHeaderParser<A>::decodeEHHdr(A &addressSpace, pint_t ehHdrStart,
|
||||
ehHdrInfo.eh_frame_ptr =
|
||||
addressSpace.getEncodedP(p, ehHdrEnd, eh_frame_ptr_enc, ehHdrStart);
|
||||
ehHdrInfo.fde_count =
|
||||
addressSpace.getEncodedP(p, ehHdrEnd, fde_count_enc, ehHdrStart);
|
||||
fde_count_enc == DW_EH_PE_omit
|
||||
? 0
|
||||
: addressSpace.getEncodedP(p, ehHdrEnd, fde_count_enc, ehHdrStart);
|
||||
ehHdrInfo.table = p;
|
||||
}
|
||||
|
||||
|
77
contrib/llvm/projects/libunwind/src/RWMutex.hpp
Normal file
77
contrib/llvm/projects/libunwind/src/RWMutex.hpp
Normal 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
@ -12,8 +12,9 @@
|
||||
|
||||
#include "Unwind-EHABI.h"
|
||||
|
||||
#if _LIBUNWIND_ARM_EHABI
|
||||
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
@ -245,11 +246,9 @@ decode_eht_entry(const uint32_t* data, size_t* off, size_t* len) {
|
||||
return data;
|
||||
}
|
||||
|
||||
_Unwind_Reason_Code _Unwind_VRS_Interpret(
|
||||
_Unwind_Context* context,
|
||||
const uint32_t* data,
|
||||
size_t offset,
|
||||
size_t len) {
|
||||
_LIBUNWIND_EXPORT _Unwind_Reason_Code
|
||||
_Unwind_VRS_Interpret(_Unwind_Context *context, const uint32_t *data,
|
||||
size_t offset, size_t len) {
|
||||
bool wrotePC = false;
|
||||
bool finish = false;
|
||||
while (offset < len && !finish) {
|
||||
@ -351,6 +350,7 @@ _Unwind_Reason_Code _Unwind_VRS_Interpret(
|
||||
}
|
||||
case 0xc0: {
|
||||
switch (byte) {
|
||||
#if defined(__ARM_WMMX)
|
||||
case 0xc0:
|
||||
case 0xc1:
|
||||
case 0xc2:
|
||||
@ -378,6 +378,7 @@ _Unwind_Reason_Code _Unwind_VRS_Interpret(
|
||||
_Unwind_VRS_Pop(context, _UVRSC_WMMXC, v, _UVRSD_DOUBLE);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case 0xc8:
|
||||
case 0xc9: {
|
||||
uint8_t v = getByte(data, offset++);
|
||||
@ -416,24 +417,21 @@ _Unwind_Reason_Code _Unwind_VRS_Interpret(
|
||||
return _URC_CONTINUE_UNWIND;
|
||||
}
|
||||
|
||||
extern "C" _Unwind_Reason_Code __aeabi_unwind_cpp_pr0(
|
||||
_Unwind_State state,
|
||||
_Unwind_Control_Block *ucbp,
|
||||
_Unwind_Context *context) {
|
||||
extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code
|
||||
__aeabi_unwind_cpp_pr0(_Unwind_State state, _Unwind_Control_Block *ucbp,
|
||||
_Unwind_Context *context) {
|
||||
return unwindOneFrame(state, ucbp, context);
|
||||
}
|
||||
|
||||
extern "C" _Unwind_Reason_Code __aeabi_unwind_cpp_pr1(
|
||||
_Unwind_State state,
|
||||
_Unwind_Control_Block *ucbp,
|
||||
_Unwind_Context *context) {
|
||||
extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code
|
||||
__aeabi_unwind_cpp_pr1(_Unwind_State state, _Unwind_Control_Block *ucbp,
|
||||
_Unwind_Context *context) {
|
||||
return unwindOneFrame(state, ucbp, context);
|
||||
}
|
||||
|
||||
extern "C" _Unwind_Reason_Code __aeabi_unwind_cpp_pr2(
|
||||
_Unwind_State state,
|
||||
_Unwind_Control_Block *ucbp,
|
||||
_Unwind_Context *context) {
|
||||
extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code
|
||||
__aeabi_unwind_cpp_pr2(_Unwind_State state, _Unwind_Control_Block *ucbp,
|
||||
_Unwind_Context *context) {
|
||||
return unwindOneFrame(state, ucbp, context);
|
||||
}
|
||||
|
||||
@ -471,11 +469,11 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
|
||||
unw_word_t pc;
|
||||
unw_get_reg(cursor, UNW_REG_IP, &pc);
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"unwind_phase1(ex_ojb=%p): pc=0x%llX, start_ip=0x%llX, func=%s, "
|
||||
"lsda=0x%llX, personality=0x%llX",
|
||||
static_cast<void *>(exception_object), (long long)pc,
|
||||
(long long)frameInfo.start_ip, functionName,
|
||||
(long long)frameInfo.lsda, (long long)frameInfo.handler);
|
||||
"unwind_phase1(ex_ojb=%p): pc=0x%" PRIxPTR ", start_ip=0x%" PRIxPTR ", func=%s, "
|
||||
"lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR,
|
||||
static_cast<void *>(exception_object), pc,
|
||||
frameInfo.start_ip, functionName,
|
||||
frameInfo.lsda, frameInfo.handler);
|
||||
}
|
||||
|
||||
// If there is a personality routine, ask it if it will want to stop at
|
||||
@ -587,11 +585,11 @@ static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor
|
||||
(frameInfo.start_ip + offset > frameInfo.end_ip))
|
||||
functionName = ".anonymous.";
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"unwind_phase2(ex_ojb=%p): start_ip=0x%llX, func=%s, sp=0x%llX, "
|
||||
"lsda=0x%llX, personality=0x%llX",
|
||||
static_cast<void *>(exception_object), (long long)frameInfo.start_ip,
|
||||
functionName, (long long)sp, (long long)frameInfo.lsda,
|
||||
(long long)frameInfo.handler);
|
||||
"unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIxPTR ", func=%s, sp=0x%" PRIxPTR ", "
|
||||
"lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR "",
|
||||
static_cast<void *>(exception_object), frameInfo.start_ip,
|
||||
functionName, sp, frameInfo.lsda,
|
||||
frameInfo.handler);
|
||||
}
|
||||
|
||||
// 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_SP, &sp);
|
||||
_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),
|
||||
(long long)pc, (long long)sp);
|
||||
pc, sp);
|
||||
}
|
||||
|
||||
{
|
||||
@ -753,7 +751,7 @@ static uint64_t ValueAsBitPattern(_Unwind_VRS_DataRepresentation representation,
|
||||
return value;
|
||||
}
|
||||
|
||||
_Unwind_VRS_Result
|
||||
_LIBUNWIND_EXPORT _Unwind_VRS_Result
|
||||
_Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
|
||||
uint32_t regno, _Unwind_VRS_DataRepresentation representation,
|
||||
void *valuep) {
|
||||
@ -771,13 +769,6 @@ _Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
|
||||
*(unw_word_t *)valuep) == UNW_ESUCCESS
|
||||
? _UVRSR_OK
|
||||
: _UVRSR_FAILED;
|
||||
case _UVRSC_WMMXC:
|
||||
if (representation != _UVRSD_UINT32 || regno > 3)
|
||||
return _UVRSR_FAILED;
|
||||
return unw_set_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno),
|
||||
*(unw_word_t *)valuep) == UNW_ESUCCESS
|
||||
? _UVRSR_OK
|
||||
: _UVRSR_FAILED;
|
||||
case _UVRSC_VFP:
|
||||
if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE)
|
||||
return _UVRSR_FAILED;
|
||||
@ -794,6 +785,14 @@ _Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
|
||||
*(unw_fpreg_t *)valuep) == UNW_ESUCCESS
|
||||
? _UVRSR_OK
|
||||
: _UVRSR_FAILED;
|
||||
#if defined(__ARM_WMMX)
|
||||
case _UVRSC_WMMXC:
|
||||
if (representation != _UVRSD_UINT32 || regno > 3)
|
||||
return _UVRSR_FAILED;
|
||||
return unw_set_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno),
|
||||
*(unw_word_t *)valuep) == UNW_ESUCCESS
|
||||
? _UVRSR_OK
|
||||
: _UVRSR_FAILED;
|
||||
case _UVRSC_WMMXD:
|
||||
if (representation != _UVRSD_DOUBLE || regno > 31)
|
||||
return _UVRSR_FAILED;
|
||||
@ -801,6 +800,11 @@ _Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
|
||||
*(unw_fpreg_t *)valuep) == UNW_ESUCCESS
|
||||
? _UVRSR_OK
|
||||
: _UVRSR_FAILED;
|
||||
#else
|
||||
case _UVRSC_WMMXC:
|
||||
case _UVRSC_WMMXD:
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
_LIBUNWIND_ABORT("unsupported register class");
|
||||
}
|
||||
@ -819,13 +823,6 @@ _Unwind_VRS_Get_Internal(_Unwind_Context *context,
|
||||
(unw_word_t *)valuep) == UNW_ESUCCESS
|
||||
? _UVRSR_OK
|
||||
: _UVRSR_FAILED;
|
||||
case _UVRSC_WMMXC:
|
||||
if (representation != _UVRSD_UINT32 || regno > 3)
|
||||
return _UVRSR_FAILED;
|
||||
return unw_get_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno),
|
||||
(unw_word_t *)valuep) == UNW_ESUCCESS
|
||||
? _UVRSR_OK
|
||||
: _UVRSR_FAILED;
|
||||
case _UVRSC_VFP:
|
||||
if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE)
|
||||
return _UVRSR_FAILED;
|
||||
@ -842,6 +839,14 @@ _Unwind_VRS_Get_Internal(_Unwind_Context *context,
|
||||
(unw_fpreg_t *)valuep) == UNW_ESUCCESS
|
||||
? _UVRSR_OK
|
||||
: _UVRSR_FAILED;
|
||||
#if defined(__ARM_WMMX)
|
||||
case _UVRSC_WMMXC:
|
||||
if (representation != _UVRSD_UINT32 || regno > 3)
|
||||
return _UVRSR_FAILED;
|
||||
return unw_get_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno),
|
||||
(unw_word_t *)valuep) == UNW_ESUCCESS
|
||||
? _UVRSR_OK
|
||||
: _UVRSR_FAILED;
|
||||
case _UVRSC_WMMXD:
|
||||
if (representation != _UVRSD_DOUBLE || regno > 31)
|
||||
return _UVRSR_FAILED;
|
||||
@ -849,16 +854,19 @@ _Unwind_VRS_Get_Internal(_Unwind_Context *context,
|
||||
(unw_fpreg_t *)valuep) == UNW_ESUCCESS
|
||||
? _UVRSR_OK
|
||||
: _UVRSR_FAILED;
|
||||
#else
|
||||
case _UVRSC_WMMXC:
|
||||
case _UVRSC_WMMXD:
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
_LIBUNWIND_ABORT("unsupported register class");
|
||||
}
|
||||
|
||||
_Unwind_VRS_Result _Unwind_VRS_Get(
|
||||
_Unwind_Context *context,
|
||||
_Unwind_VRS_RegClass regclass,
|
||||
uint32_t regno,
|
||||
_Unwind_VRS_DataRepresentation representation,
|
||||
void *valuep) {
|
||||
_LIBUNWIND_EXPORT _Unwind_VRS_Result
|
||||
_Unwind_VRS_Get(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
|
||||
uint32_t regno, _Unwind_VRS_DataRepresentation representation,
|
||||
void *valuep) {
|
||||
_Unwind_VRS_Result result =
|
||||
_Unwind_VRS_Get_Internal(context, regclass, regno, representation,
|
||||
valuep);
|
||||
@ -879,8 +887,11 @@ _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
|
||||
static_cast<void *>(context), regclass, discriminator,
|
||||
representation);
|
||||
switch (regclass) {
|
||||
case _UVRSC_CORE:
|
||||
case _UVRSC_WMMXC: {
|
||||
case _UVRSC_WMMXC:
|
||||
#if !defined(__ARM_WMMX)
|
||||
break;
|
||||
#endif
|
||||
case _UVRSC_CORE: {
|
||||
if (representation != _UVRSD_UINT32)
|
||||
return _UVRSR_FAILED;
|
||||
// When popping SP from the stack, we don't want to override it from the
|
||||
@ -908,8 +919,11 @@ _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
|
||||
}
|
||||
return _UVRSR_OK;
|
||||
}
|
||||
case _UVRSC_VFP:
|
||||
case _UVRSC_WMMXD: {
|
||||
case _UVRSC_WMMXD:
|
||||
#if !defined(__ARM_WMMX)
|
||||
break;
|
||||
#endif
|
||||
case _UVRSC_VFP: {
|
||||
if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE)
|
||||
return _UVRSR_FAILED;
|
||||
uint32_t first = discriminator >> 16;
|
||||
@ -974,4 +988,4 @@ __gnu_unwind_frame(_Unwind_Exception *exception_object,
|
||||
return _URC_OK;
|
||||
}
|
||||
|
||||
#endif // _LIBUNWIND_ARM_EHABI
|
||||
#endif // defined(_LIBUNWIND_ARM_EHABI)
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
#include <__libunwind_config.h>
|
||||
|
||||
#if _LIBUNWIND_ARM_EHABI
|
||||
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unwind.h>
|
||||
@ -46,6 +46,6 @@ extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr2(
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _LIBUNWIND_ARM_EHABI
|
||||
#endif // defined(_LIBUNWIND_ARM_EHABI)
|
||||
|
||||
#endif // __UNWIND_EHABI_H__
|
||||
|
491
contrib/llvm/projects/libunwind/src/Unwind-seh.cpp
Normal file
491
contrib/llvm/projects/libunwind/src/Unwind-seh.cpp
Normal 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)
|
@ -17,32 +17,26 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "unwind_ext.h"
|
||||
|
||||
//
|
||||
// 32-bit iOS uses setjump/longjump based C++ exceptions.
|
||||
// Other architectures use "zero cost" exceptions.
|
||||
//
|
||||
// With SJLJ based exceptions, any function that has a catch clause or needs to
|
||||
// do any clean up when an exception propagates through it, needs to call
|
||||
// _Unwind_SjLj_Register() at the start of the function and
|
||||
// _Unwind_SjLj_Unregister() at the end. The register function is called with
|
||||
// the address of a block of memory in the function's stack frame. The runtime
|
||||
// keeps a linked list (stack) of these blocks - one per thread. The calling
|
||||
// function also sets the personality and lsda fields of the block.
|
||||
//
|
||||
/// With SJLJ based exceptions, any function that has a catch clause or needs to
|
||||
/// do any clean up when an exception propagates through it, needs to call
|
||||
/// \c _Unwind_SjLj_Register at the start of the function and
|
||||
/// \c _Unwind_SjLj_Unregister at the end. The register function is called with
|
||||
/// the address of a block of memory in the function's stack frame. The runtime
|
||||
/// keeps a linked list (stack) of these blocks - one per thread. The calling
|
||||
/// function also sets the personality and lsda fields of the block.
|
||||
|
||||
#if _LIBUNWIND_BUILD_SJLJ_APIS
|
||||
#if defined(_LIBUNWIND_BUILD_SJLJ_APIS)
|
||||
|
||||
struct _Unwind_FunctionContext {
|
||||
// next function in stack of handlers
|
||||
struct _Unwind_FunctionContext *prev;
|
||||
|
||||
// set by calling function before registering to be the landing pad
|
||||
uintptr_t resumeLocation;
|
||||
uint32_t resumeLocation;
|
||||
|
||||
// set by personality handler to be parameters passed to landing pad function
|
||||
uintptr_t resumeParameters[4];
|
||||
uint32_t resumeParameters[4];
|
||||
|
||||
// set by calling function before registering
|
||||
__personality_routine personality; // arm offset=24
|
||||
@ -53,6 +47,48 @@ struct _Unwind_FunctionContext {
|
||||
void *jbuf[];
|
||||
};
|
||||
|
||||
#if defined(_LIBUNWIND_HAS_NO_THREADS)
|
||||
# define _LIBUNWIND_THREAD_LOCAL
|
||||
#else
|
||||
# if __STDC_VERSION__ >= 201112L
|
||||
# define _LIBUNWIND_THREAD_LOCAL _Thread_local
|
||||
# elif defined(_WIN32)
|
||||
# define _LIBUNWIND_THREAD_LOCAL __declspec(thread)
|
||||
# elif defined(__GNUC__) || defined(__clang__)
|
||||
# define _LIBUNWIND_THREAD_LOCAL __thread
|
||||
# else
|
||||
# error Unable to create thread local storage
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(FOR_DYLD)
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <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
|
||||
_LIBUNWIND_EXPORT void
|
||||
@ -465,4 +501,4 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // _LIBUNWIND_BUILD_SJLJ_APIS
|
||||
#endif // defined(_LIBUNWIND_BUILD_SJLJ_APIS)
|
||||
|
@ -16,13 +16,53 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <unwind.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <ntverp.h>
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
#include <mach-o/dyld.h>
|
||||
#endif
|
||||
|
||||
#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
|
||||
// Provide a definition for the DISPATCHER_CONTEXT struct for old (Win7 and
|
||||
// earlier) SDKs.
|
||||
// MinGW-w64 has always provided this struct.
|
||||
#if defined(_WIN32) && defined(_LIBUNWIND_TARGET_X86_64) && \
|
||||
!defined(__MINGW32__) && VER_PRODUCTBUILD < 8000
|
||||
struct _DISPATCHER_CONTEXT {
|
||||
ULONG64 ControlPc;
|
||||
ULONG64 ImageBase;
|
||||
PRUNTIME_FUNCTION FunctionEntry;
|
||||
ULONG64 EstablisherFrame;
|
||||
ULONG64 TargetIp;
|
||||
PCONTEXT ContextRecord;
|
||||
PEXCEPTION_ROUTINE LanguageHandler;
|
||||
PVOID HandlerData;
|
||||
PUNWIND_HISTORY_TABLE HistoryTable;
|
||||
ULONG ScopeIndex;
|
||||
ULONG Fill0;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct UNWIND_INFO {
|
||||
uint8_t Version : 3;
|
||||
uint8_t Flags : 5;
|
||||
uint8_t SizeOfProlog;
|
||||
uint8_t CountOfCodes;
|
||||
uint8_t FrameRegister : 4;
|
||||
uint8_t FrameOffset : 4;
|
||||
uint16_t UnwindCodes[2];
|
||||
};
|
||||
|
||||
extern "C" _Unwind_Reason_Code __libunwind_seh_personality(
|
||||
int, _Unwind_Action, uint64_t, _Unwind_Exception *,
|
||||
struct _Unwind_Context *);
|
||||
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "AddressSpace.hpp"
|
||||
@ -32,11 +72,12 @@
|
||||
#include "EHHeaderParser.hpp"
|
||||
#include "libunwind.h"
|
||||
#include "Registers.hpp"
|
||||
#include "RWMutex.hpp"
|
||||
#include "Unwind-EHABI.h"
|
||||
|
||||
namespace libunwind {
|
||||
|
||||
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
|
||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||
/// Cache of recently found FDEs.
|
||||
template <typename A>
|
||||
class _LIBUNWIND_HIDDEN DwarfFDECache {
|
||||
@ -60,7 +101,7 @@ class _LIBUNWIND_HIDDEN DwarfFDECache {
|
||||
|
||||
// These fields are all static to avoid needing an initializer.
|
||||
// There is only one instance of this class per process.
|
||||
static pthread_rwlock_t _lock;
|
||||
static RWMutex _lock;
|
||||
#ifdef __APPLE__
|
||||
static void dyldUnloadHook(const struct mach_header *mh, intptr_t slide);
|
||||
static bool _registeredForDyldUnloads;
|
||||
@ -88,7 +129,7 @@ template <typename A>
|
||||
typename DwarfFDECache<A>::entry DwarfFDECache<A>::_initialBuffer[64];
|
||||
|
||||
template <typename A>
|
||||
pthread_rwlock_t DwarfFDECache<A>::_lock = PTHREAD_RWLOCK_INITIALIZER;
|
||||
RWMutex DwarfFDECache<A>::_lock;
|
||||
|
||||
#ifdef __APPLE__
|
||||
template <typename A>
|
||||
@ -98,7 +139,7 @@ bool DwarfFDECache<A>::_registeredForDyldUnloads = false;
|
||||
template <typename A>
|
||||
typename A::pint_t DwarfFDECache<A>::findFDE(pint_t mh, pint_t pc) {
|
||||
pint_t result = 0;
|
||||
_LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_rdlock(&_lock));
|
||||
_LIBUNWIND_LOG_IF_FALSE(_lock.lock_shared());
|
||||
for (entry *p = _buffer; p < _bufferUsed; ++p) {
|
||||
if ((mh == p->mh) || (mh == 0)) {
|
||||
if ((p->ip_start <= pc) && (pc < p->ip_end)) {
|
||||
@ -107,7 +148,7 @@ typename A::pint_t DwarfFDECache<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;
|
||||
}
|
||||
|
||||
@ -115,7 +156,7 @@ template <typename A>
|
||||
void DwarfFDECache<A>::add(pint_t mh, pint_t ip_start, pint_t ip_end,
|
||||
pint_t fde) {
|
||||
#if !defined(_LIBUNWIND_NO_HEAP)
|
||||
_LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock));
|
||||
_LIBUNWIND_LOG_IF_FALSE(_lock.lock());
|
||||
if (_bufferUsed >= _bufferEnd) {
|
||||
size_t oldSize = (size_t)(_bufferEnd - _buffer);
|
||||
size_t newSize = oldSize * 4;
|
||||
@ -139,13 +180,13 @@ void DwarfFDECache<A>::add(pint_t mh, pint_t ip_start, pint_t ip_end,
|
||||
_registeredForDyldUnloads = true;
|
||||
}
|
||||
#endif
|
||||
_LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock));
|
||||
_LIBUNWIND_LOG_IF_FALSE(_lock.unlock());
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename A>
|
||||
void DwarfFDECache<A>::removeAllIn(pint_t mh) {
|
||||
_LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock));
|
||||
_LIBUNWIND_LOG_IF_FALSE(_lock.lock());
|
||||
entry *d = _buffer;
|
||||
for (const entry *s = _buffer; s < _bufferUsed; ++s) {
|
||||
if (s->mh != mh) {
|
||||
@ -155,7 +196,7 @@ void DwarfFDECache<A>::removeAllIn(pint_t mh) {
|
||||
}
|
||||
}
|
||||
_bufferUsed = d;
|
||||
_LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock));
|
||||
_LIBUNWIND_LOG_IF_FALSE(_lock.unlock());
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
@ -168,18 +209,18 @@ void DwarfFDECache<A>::dyldUnloadHook(const struct mach_header *mh, intptr_t ) {
|
||||
template <typename A>
|
||||
void DwarfFDECache<A>::iterateCacheEntries(void (*func)(
|
||||
unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) {
|
||||
_LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock));
|
||||
_LIBUNWIND_LOG_IF_FALSE(_lock.lock());
|
||||
for (entry *p = _buffer; p < _bufferUsed; ++p) {
|
||||
(*func)(p->ip_start, p->ip_end, p->fde, p->mh);
|
||||
}
|
||||
_LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock));
|
||||
_LIBUNWIND_LOG_IF_FALSE(_lock.unlock());
|
||||
}
|
||||
#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND
|
||||
#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||
|
||||
|
||||
#define arrayoffsetof(type, index, field) ((size_t)(&((type *)0)[index].field))
|
||||
|
||||
#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND
|
||||
#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
|
||||
template <typename A> class UnwindSectionHeader {
|
||||
public:
|
||||
UnwindSectionHeader(A &addressSpace, typename A::pint_t addr)
|
||||
@ -367,7 +408,7 @@ template <typename A> class UnwindSectionLsdaArray {
|
||||
A &_addressSpace;
|
||||
typename A::pint_t _addr;
|
||||
};
|
||||
#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND
|
||||
#endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
|
||||
|
||||
class _LIBUNWIND_HIDDEN AbstractUnwindCursor {
|
||||
public:
|
||||
@ -412,6 +453,419 @@ class _LIBUNWIND_HIDDEN AbstractUnwindCursor {
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
|
||||
|
||||
/// \c UnwindCursor contains all state (including all register values) during
|
||||
/// an unwind. This is normally stack-allocated inside a unw_cursor_t.
|
||||
template <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
|
||||
/// an unwind. This is normally stack allocated inside a unw_cursor_t.
|
||||
template <typename A, typename R>
|
||||
@ -440,7 +894,7 @@ class UnwindCursor : public AbstractUnwindCursor{
|
||||
|
||||
private:
|
||||
|
||||
#if _LIBUNWIND_ARM_EHABI
|
||||
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||
bool getInfoFromEHABISection(pint_t pc, const UnwindInfoSections §s);
|
||||
|
||||
int stepWithEHABI() {
|
||||
@ -458,7 +912,7 @@ class UnwindCursor : public AbstractUnwindCursor{
|
||||
}
|
||||
#endif
|
||||
|
||||
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
|
||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||
bool getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections §s,
|
||||
uint32_t fdeSectionOffsetHint=0);
|
||||
int stepWithDwarfFDE() {
|
||||
@ -469,11 +923,11 @@ class UnwindCursor : public AbstractUnwindCursor{
|
||||
}
|
||||
#endif
|
||||
|
||||
#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND
|
||||
#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
|
||||
bool getInfoFromCompactEncodingSection(pint_t pc,
|
||||
const UnwindInfoSections §s);
|
||||
int stepWithCompactEncoding() {
|
||||
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
|
||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||
if ( compactSaysUseDwarf() )
|
||||
return stepWithDwarfFDE();
|
||||
#endif
|
||||
@ -501,6 +955,13 @@ class UnwindCursor : public AbstractUnwindCursor{
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_LIBUNWIND_TARGET_PPC64)
|
||||
int stepWithCompactEncoding(Registers_ppc64 &) {
|
||||
return UNW_EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(_LIBUNWIND_TARGET_AARCH64)
|
||||
int stepWithCompactEncoding(Registers_arm64 &) {
|
||||
return CompactUnwinder_arm64<A>::stepWithCompactEncoding(
|
||||
@ -520,6 +981,10 @@ class UnwindCursor : public AbstractUnwindCursor{
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_LIBUNWIND_TARGET_SPARC)
|
||||
int stepWithCompactEncoding(Registers_sparc &) { return UNW_EINVAL; }
|
||||
#endif
|
||||
|
||||
bool compactSaysUseDwarf(uint32_t *offset=NULL) const {
|
||||
R dummy;
|
||||
return compactSaysUseDwarf(dummy, offset);
|
||||
@ -553,6 +1018,12 @@ class UnwindCursor : public AbstractUnwindCursor{
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_LIBUNWIND_TARGET_PPC64)
|
||||
bool compactSaysUseDwarf(Registers_ppc64 &, uint32_t *) const {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_LIBUNWIND_TARGET_AARCH64)
|
||||
bool compactSaysUseDwarf(Registers_arm64 &, uint32_t *offset) const {
|
||||
if ((_info.format & UNWIND_ARM64_MODE_MASK) == UNWIND_ARM64_MODE_DWARF) {
|
||||
@ -575,9 +1046,14 @@ class UnwindCursor : public AbstractUnwindCursor{
|
||||
return true;
|
||||
}
|
||||
#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 {
|
||||
R dummy;
|
||||
return dwarfEncoding(dummy);
|
||||
@ -601,12 +1077,24 @@ class UnwindCursor : public AbstractUnwindCursor{
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_LIBUNWIND_TARGET_PPC64)
|
||||
compact_unwind_encoding_t dwarfEncoding(Registers_ppc64 &) const {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_LIBUNWIND_TARGET_AARCH64)
|
||||
compact_unwind_encoding_t dwarfEncoding(Registers_arm64 &) const {
|
||||
return UNWIND_ARM64_MODE_DWARF;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_LIBUNWIND_TARGET_ARM)
|
||||
compact_unwind_encoding_t dwarfEncoding(Registers_arm &) const {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (_LIBUNWIND_TARGET_OR1K)
|
||||
compact_unwind_encoding_t dwarfEncoding(Registers_or1k &) const {
|
||||
return 0;
|
||||
@ -630,7 +1118,26 @@ class UnwindCursor : public AbstractUnwindCursor{
|
||||
return 0;
|
||||
}
|
||||
#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;
|
||||
@ -708,7 +1215,9 @@ template <typename A, typename R> bool UnwindCursor<A, R>::isSignalFrame() {
|
||||
return _isSignalFrame;
|
||||
}
|
||||
|
||||
#if _LIBUNWIND_ARM_EHABI
|
||||
#endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
|
||||
|
||||
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||
struct EHABIIndexEntry {
|
||||
uint32_t functionOffset;
|
||||
uint32_t data;
|
||||
@ -729,7 +1238,8 @@ struct EHABISectionIterator {
|
||||
return _Self(addressSpace, sects, 0);
|
||||
}
|
||||
static _Self end(A& addressSpace, const UnwindInfoSections& sects) {
|
||||
return _Self(addressSpace, sects, sects.arm_section_length);
|
||||
return _Self(addressSpace, sects,
|
||||
sects.arm_section_length / sizeof(EHABIIndexEntry));
|
||||
}
|
||||
|
||||
EHABISectionIterator(A& addressSpace, const UnwindInfoSections& sects, size_t i)
|
||||
@ -779,14 +1289,21 @@ bool UnwindCursor<A, R>::getInfoFromEHABISection(
|
||||
EHABISectionIterator<A>::begin(_addressSpace, sects);
|
||||
EHABISectionIterator<A> end =
|
||||
EHABISectionIterator<A>::end(_addressSpace, sects);
|
||||
if (begin == end)
|
||||
return false;
|
||||
|
||||
EHABISectionIterator<A> itNextPC = std::upper_bound(begin, end, pc);
|
||||
if (itNextPC == begin || itNextPC == end)
|
||||
if (itNextPC == begin)
|
||||
return false;
|
||||
EHABISectionIterator<A> itThisPC = itNextPC - 1;
|
||||
|
||||
pint_t thisPC = itThisPC.functionAddress();
|
||||
pint_t nextPC = itNextPC.functionAddress();
|
||||
// If an exception is thrown from a function, corresponding to the last entry
|
||||
// in the table, we don't really know the function extent and have to choose a
|
||||
// value for nextPC. Choosing max() will allow the range check during trace to
|
||||
// succeed.
|
||||
pint_t nextPC = (itNextPC == end) ? std::numeric_limits<pint_t>::max()
|
||||
: itNextPC.functionAddress();
|
||||
pint_t indexDataAddr = itThisPC.dataAddress();
|
||||
|
||||
if (indexDataAddr == 0)
|
||||
@ -903,7 +1420,7 @@ bool UnwindCursor<A, R>::getInfoFromEHABISection(
|
||||
}
|
||||
#endif
|
||||
|
||||
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
|
||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||
template <typename A, typename R>
|
||||
bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
|
||||
const UnwindInfoSections §s,
|
||||
@ -919,7 +1436,7 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
|
||||
sects.dwarf_section + fdeSectionOffsetHint,
|
||||
&fdeInfo, &cieInfo);
|
||||
}
|
||||
#if _LIBUNWIND_SUPPORT_DWARF_INDEX
|
||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
|
||||
if (!foundFDE && (sects.dwarf_index_section != 0)) {
|
||||
foundFDE = EHHeaderParser<A>::findFDE(
|
||||
_addressSpace, pc, sects.dwarf_index_section,
|
||||
@ -946,7 +1463,7 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
|
||||
if (foundFDE) {
|
||||
typename CFI_Parser<A>::PrologInfo prolog;
|
||||
if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc,
|
||||
&prolog)) {
|
||||
R::getArch(), &prolog)) {
|
||||
// Save off parsed FDE info
|
||||
_info.start_ip = fdeInfo.pcStart;
|
||||
_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
|
||||
// and there was no index.
|
||||
if (!foundInCache && (fdeSectionOffsetHint == 0)) {
|
||||
#if _LIBUNWIND_SUPPORT_DWARF_INDEX
|
||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
|
||||
if (sects.dwarf_index_section == 0)
|
||||
#endif
|
||||
DwarfFDECache<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);
|
||||
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>
|
||||
bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(pint_t pc,
|
||||
const UnwindInfoSections §s) {
|
||||
@ -1231,13 +1748,62 @@ bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(pint_t pc,
|
||||
_info.extra = sects.dso_base;
|
||||
return true;
|
||||
}
|
||||
#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND
|
||||
#endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
|
||||
|
||||
|
||||
#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
|
||||
template <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>
|
||||
void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
|
||||
pint_t pc = (pint_t)this->getReg(UNW_REG_IP);
|
||||
#if _LIBUNWIND_ARM_EHABI
|
||||
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||
// Remove the thumb bit so the IP represents the actual instruction address.
|
||||
// This matches the behaviour of _Unwind_GetIP on arm.
|
||||
pc &= (pint_t)~0x1;
|
||||
@ -1254,11 +1820,11 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
|
||||
// Ask address space object to find unwind sections for this pc.
|
||||
UnwindInfoSections sects;
|
||||
if (_addressSpace.findUnwindSections(pc, sects)) {
|
||||
#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND
|
||||
#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
|
||||
// If there is a compact unwind encoding table, look there first.
|
||||
if (sects.compact_unwind_section != 0) {
|
||||
if (this->getInfoFromCompactEncodingSection(pc, sects)) {
|
||||
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
|
||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||
// Found info in table, done unless encoding says to use dwarf.
|
||||
uint32_t dwarfOffset;
|
||||
if ((sects.dwarf_section != 0) && compactSaysUseDwarf(&dwarfOffset)) {
|
||||
@ -1275,9 +1841,15 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND
|
||||
#endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
|
||||
|
||||
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
|
||||
#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
|
||||
// If there is SEH unwind info, look there next.
|
||||
if (this->getInfoFromSEH(pc))
|
||||
return;
|
||||
#endif
|
||||
|
||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||
// If there is dwarf unwind info, look there next.
|
||||
if (sects.dwarf_section != 0) {
|
||||
if (this->getInfoFromDwarfSection(pc, sects)) {
|
||||
@ -1287,14 +1859,14 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if _LIBUNWIND_ARM_EHABI
|
||||
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||
// If there is ARM EHABI unwind info, look there next.
|
||||
if (sects.arm_section != 0 && this->getInfoFromEHABISection(pc, sects))
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
|
||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||
// There is no static unwind info for this pc. Look to see if an FDE was
|
||||
// dynamically registered for it.
|
||||
pint_t cachedFDE = DwarfFDECache<A>::findFDE(0, pc);
|
||||
@ -1306,7 +1878,7 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
|
||||
if (msg == NULL) {
|
||||
typename CFI_Parser<A>::PrologInfo prolog;
|
||||
if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo,
|
||||
pc, &prolog)) {
|
||||
pc, R::getArch(), &prolog)) {
|
||||
// save off parsed FDE info
|
||||
_info.start_ip = fdeInfo.pcStart;
|
||||
_info.end_ip = fdeInfo.pcEnd;
|
||||
@ -1335,8 +1907,8 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
|
||||
// Double check this FDE is for a function that includes the pc.
|
||||
if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd)) {
|
||||
typename CFI_Parser<A>::PrologInfo prolog;
|
||||
if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo,
|
||||
cieInfo, pc, &prolog)) {
|
||||
if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo,
|
||||
pc, R::getArch(), &prolog)) {
|
||||
// save off parsed FDE info
|
||||
_info.start_ip = fdeInfo.pcStart;
|
||||
_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
|
||||
_unwindInfoMissing = true;
|
||||
@ -1367,14 +1939,17 @@ int UnwindCursor<A, R>::step() {
|
||||
|
||||
// Use unwinding info to modify register set as if function returned.
|
||||
int result;
|
||||
#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND
|
||||
#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
|
||||
result = this->stepWithCompactEncoding();
|
||||
#elif _LIBUNWIND_SUPPORT_DWARF_UNWIND
|
||||
#elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
|
||||
result = this->stepWithSEHData();
|
||||
#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||
result = this->stepWithDwarfFDE();
|
||||
#elif _LIBUNWIND_ARM_EHABI
|
||||
#elif defined(_LIBUNWIND_ARM_EHABI)
|
||||
result = this->stepWithEHABI();
|
||||
#else
|
||||
#error Need _LIBUNWIND_SUPPORT_COMPACT_UNWIND or \
|
||||
_LIBUNWIND_SUPPORT_SEH_UNWIND or \
|
||||
_LIBUNWIND_SUPPORT_DWARF_UNWIND or \
|
||||
_LIBUNWIND_ARM_EHABI
|
||||
#endif
|
||||
@ -1384,8 +1959,6 @@ int UnwindCursor<A, R>::step() {
|
||||
this->setInfoBasedOnIPRegister(true);
|
||||
if (_unwindInfoMissing)
|
||||
return UNW_STEP_END;
|
||||
if (_info.gp)
|
||||
setReg(UNW_REG_SP, getReg(UNW_REG_SP) + _info.gp);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -23,22 +23,26 @@
|
||||
#include "Unwind-EHABI.h"
|
||||
#include "unwind.h"
|
||||
|
||||
#if _LIBUNWIND_BUILD_ZERO_COST_APIS
|
||||
#if defined(_LIBUNWIND_BUILD_ZERO_COST_APIS)
|
||||
|
||||
#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
|
||||
#define private_1 private_[0]
|
||||
#endif
|
||||
|
||||
/// Called by __cxa_rethrow().
|
||||
_LIBUNWIND_EXPORT _Unwind_Reason_Code
|
||||
_Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object) {
|
||||
#if _LIBUNWIND_ARM_EHABI
|
||||
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||
_LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%ld",
|
||||
(void *)exception_object,
|
||||
(long)exception_object->unwinder_cache.reserved1);
|
||||
#else
|
||||
_LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%ld",
|
||||
_LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%" PRIdPTR,
|
||||
(void *)exception_object,
|
||||
(long)exception_object->private_1);
|
||||
(intptr_t)exception_object->private_1);
|
||||
#endif
|
||||
|
||||
#if _LIBUNWIND_ARM_EHABI
|
||||
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||
// _Unwind_RaiseException on EHABI will always set the reserved1 field to 0,
|
||||
// which is in the same position as private_1 below.
|
||||
return _Unwind_RaiseException(exception_object);
|
||||
@ -92,9 +96,9 @@ _LIBUNWIND_EXPORT void *_Unwind_FindEnclosingFunction(void *pc) {
|
||||
unw_proc_info_t info;
|
||||
unw_getcontext(&uc);
|
||||
unw_init_local(&cursor, &uc);
|
||||
unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(long) pc);
|
||||
unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(intptr_t) pc);
|
||||
if (unw_get_proc_info(&cursor, &info) == UNW_ESUCCESS)
|
||||
return (void *)(long) info.start_ip;
|
||||
return (void *)(intptr_t) info.start_ip;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
@ -111,7 +115,7 @@ _Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) {
|
||||
_LIBUNWIND_TRACE_API("_Unwind_Backtrace(callback=%p)",
|
||||
(void *)(uintptr_t)callback);
|
||||
|
||||
#if _LIBUNWIND_ARM_EHABI
|
||||
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||
// Create a mock exception object for force unwinding.
|
||||
_Unwind_Exception ex;
|
||||
memset(&ex, '\0', sizeof(ex));
|
||||
@ -122,7 +126,7 @@ _Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) {
|
||||
while (true) {
|
||||
_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
|
||||
// _Unwind_Backtrace())
|
||||
if (unw_step(&cursor) <= 0) {
|
||||
@ -154,7 +158,7 @@ _Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) {
|
||||
_URC_CONTINUE_UNWIND) {
|
||||
return _URC_END_OF_STACK;
|
||||
}
|
||||
#endif // _LIBUNWIND_ARM_EHABI
|
||||
#endif // defined(_LIBUNWIND_ARM_EHABI)
|
||||
|
||||
// debugging
|
||||
if (_LIBUNWIND_TRACING_UNWINDING) {
|
||||
@ -164,8 +168,8 @@ _Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) {
|
||||
unw_get_proc_name(&cursor, functionName, 512, &offset);
|
||||
unw_get_proc_info(&cursor, &frame);
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
" _backtrace: start_ip=0x%llX, func=%s, lsda=0x%llX, context=%p",
|
||||
(long long)frame.start_ip, functionName, (long long)frame.lsda,
|
||||
" _backtrace: start_ip=0x%" PRIxPTR ", func=%s, lsda=0x%" PRIxPTR ", context=%p",
|
||||
frame.start_ip, functionName, frame.lsda,
|
||||
(void *)&cursor);
|
||||
}
|
||||
|
||||
@ -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,
|
||||
struct dwarf_eh_bases *bases) {
|
||||
// This is slow, but works.
|
||||
@ -190,14 +194,14 @@ _LIBUNWIND_EXPORT const void *_Unwind_Find_FDE(const void *pc,
|
||||
unw_proc_info_t info;
|
||||
unw_getcontext(&uc);
|
||||
unw_init_local(&cursor, &uc);
|
||||
unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(long) pc);
|
||||
unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(intptr_t) pc);
|
||||
unw_get_proc_info(&cursor, &info);
|
||||
bases->tbase = (uintptr_t)info.extra;
|
||||
bases->dbase = 0; // dbase not used on Mac OS X
|
||||
bases->func = (uintptr_t)info.start_ip;
|
||||
_LIBUNWIND_TRACE_API("_Unwind_Find_FDE(pc=%p) => %p", pc,
|
||||
(void *)(long) info.unwind_info);
|
||||
return (void *)(long) info.unwind_info;
|
||||
(void *)(intptr_t) info.unwind_info);
|
||||
return (void *)(intptr_t) info.unwind_info;
|
||||
}
|
||||
|
||||
/// Returns the CFA (call frame area, or stack pointer at start of function)
|
||||
@ -206,8 +210,8 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) {
|
||||
unw_cursor_t *cursor = (unw_cursor_t *)context;
|
||||
unw_word_t result;
|
||||
unw_get_reg(cursor, UNW_REG_SP, &result);
|
||||
_LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p) => 0x%" PRIx64,
|
||||
(void *)context, (uint64_t)result);
|
||||
_LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p) => 0x%" PRIxPTR,
|
||||
(void *)context, result);
|
||||
return (uintptr_t)result;
|
||||
}
|
||||
|
||||
@ -222,7 +226,7 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context,
|
||||
return _Unwind_GetIP(context);
|
||||
}
|
||||
|
||||
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
|
||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||
|
||||
#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
|
||||
// application won't be able to use them.
|
||||
|
||||
#if _LIBUNWIND_SUPPORT_FRAME_APIS
|
||||
#if defined(_LIBUNWIND_SUPPORT_FRAME_APIS)
|
||||
_LIBUNWIND_EXPORT void __register_frame_info_bases(const void *fde, void *ob,
|
||||
void *tb, void *db) {
|
||||
(void)fde;
|
||||
@ -351,8 +355,8 @@ _LIBUNWIND_EXPORT void *__deregister_frame_info_bases(const void *fde) {
|
||||
// do nothing, this function never worked in Mac OS X
|
||||
return NULL;
|
||||
}
|
||||
#endif // _LIBUNWIND_SUPPORT_FRAME_APIS
|
||||
#endif // defined(_LIBUNWIND_SUPPORT_FRAME_APIS)
|
||||
|
||||
#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND
|
||||
#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||
|
||||
#endif // _LIBUNWIND_BUILD_ZERO_COST_APIS
|
||||
#endif // defined(_LIBUNWIND_BUILD_ZERO_COST_APIS)
|
||||
|
@ -30,7 +30,9 @@
|
||||
#include "unwind.h"
|
||||
#include "config.h"
|
||||
|
||||
#if !_LIBUNWIND_ARM_EHABI
|
||||
#if !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__)
|
||||
|
||||
#ifndef _LIBUNWIND_SUPPORT_SEH_UNWIND
|
||||
|
||||
static _Unwind_Reason_Code
|
||||
unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) {
|
||||
@ -76,8 +78,8 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
|
||||
unw_word_t pc;
|
||||
unw_get_reg(cursor, UNW_REG_IP, &pc);
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"unwind_phase1(ex_ojb=%p): pc=0x%" PRIx64 ", start_ip=0x%" PRIx64
|
||||
", func=%s, lsda=0x%" PRIx64 ", personality=0x%" PRIx64 "",
|
||||
"unwind_phase1(ex_ojb=%p): pc=0x%" PRIxPTR ", start_ip=0x%" PRIxPTR
|
||||
", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR "",
|
||||
(void *)exception_object, pc, frameInfo.start_ip, functionName,
|
||||
frameInfo.lsda, frameInfo.handler);
|
||||
}
|
||||
@ -86,7 +88,7 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
|
||||
// this frame.
|
||||
if (frameInfo.handler != 0) {
|
||||
__personality_routine p =
|
||||
(__personality_routine)(long)(frameInfo.handler);
|
||||
(__personality_routine)(uintptr_t)(frameInfo.handler);
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"unwind_phase1(ex_ojb=%p): calling personality function %p",
|
||||
(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) ||
|
||||
(frameInfo.start_ip + offset > frameInfo.end_ip))
|
||||
functionName = ".anonymous.";
|
||||
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIx64
|
||||
", func=%s, sp=0x%" PRIx64 ", lsda=0x%" PRIx64
|
||||
", personality=0x%" PRIx64,
|
||||
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIxPTR
|
||||
", func=%s, sp=0x%" PRIxPTR ", lsda=0x%" PRIxPTR
|
||||
", personality=0x%" PRIxPTR,
|
||||
(void *)exception_object, frameInfo.start_ip,
|
||||
functionName, sp, frameInfo.lsda,
|
||||
frameInfo.handler);
|
||||
@ -181,7 +183,7 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
|
||||
// If there is a personality routine, tell it we are unwinding.
|
||||
if (frameInfo.handler != 0) {
|
||||
__personality_routine p =
|
||||
(__personality_routine)(long)(frameInfo.handler);
|
||||
(__personality_routine)(uintptr_t)(frameInfo.handler);
|
||||
_Unwind_Action action = _UA_CLEANUP_PHASE;
|
||||
if (sp == exception_object->private_2) {
|
||||
// Tell personality this was the frame it marked in phase 1.
|
||||
@ -213,8 +215,8 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
|
||||
unw_get_reg(cursor, UNW_REG_IP, &pc);
|
||||
unw_get_reg(cursor, UNW_REG_SP, &sp);
|
||||
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering "
|
||||
"user code with ip=0x%" PRIx64
|
||||
", sp=0x%" PRIx64,
|
||||
"user code with ip=0x%" PRIxPTR
|
||||
", sp=0x%" PRIxPTR,
|
||||
(void *)exception_object, pc, sp);
|
||||
}
|
||||
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))
|
||||
functionName = ".anonymous.";
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIx64
|
||||
", func=%s, lsda=0x%" PRIx64 ", personality=0x%" PRIx64,
|
||||
"unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIxPTR
|
||||
", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR,
|
||||
(void *)exception_object, frameInfo.start_ip, functionName,
|
||||
frameInfo.lsda, frameInfo.handler);
|
||||
}
|
||||
@ -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 (frameInfo.handler != 0) {
|
||||
__personality_routine p =
|
||||
(__personality_routine)(long)(frameInfo.handler);
|
||||
(__personality_routine)(intptr_t)(frameInfo.handler);
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"unwind_phase2_forced(ex_ojb=%p): calling personality function %p",
|
||||
(void *)exception_object, (void *)(uintptr_t)p);
|
||||
@ -449,6 +451,7 @@ _Unwind_GetRegionStart(struct _Unwind_Context *context) {
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // !_LIBUNWIND_SUPPORT_SEH_UNWIND
|
||||
|
||||
/// Called by personality handler during phase 2 if a foreign exception
|
||||
// is caught.
|
||||
@ -467,17 +470,17 @@ _Unwind_GetGR(struct _Unwind_Context *context, int index) {
|
||||
unw_cursor_t *cursor = (unw_cursor_t *)context;
|
||||
unw_word_t result;
|
||||
unw_get_reg(cursor, index, &result);
|
||||
_LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%" PRIx64,
|
||||
(void *)context, index, (uint64_t)result);
|
||||
_LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%" PRIxPTR,
|
||||
(void *)context, index, result);
|
||||
return (uintptr_t)result;
|
||||
}
|
||||
|
||||
/// Called by personality handler during phase 2 to alter register values.
|
||||
_LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index,
|
||||
uintptr_t value) {
|
||||
_LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0" PRIx64
|
||||
_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_set_reg(cursor, index, value);
|
||||
}
|
||||
@ -487,8 +490,8 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
|
||||
unw_cursor_t *cursor = (unw_cursor_t *)context;
|
||||
unw_word_t result;
|
||||
unw_get_reg(cursor, UNW_REG_IP, &result);
|
||||
_LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIx64,
|
||||
(void *)context, (uint64_t)result);
|
||||
_LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIxPTR,
|
||||
(void *)context, result);
|
||||
return (uintptr_t)result;
|
||||
}
|
||||
|
||||
@ -497,10 +500,10 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
|
||||
/// start executing in the landing pad.
|
||||
_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context,
|
||||
uintptr_t value) {
|
||||
_LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0" PRIx64 ")",
|
||||
(void *)context, (uint64_t)value);
|
||||
_LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0" PRIxPTR ")",
|
||||
(void *)context, value);
|
||||
unw_cursor_t *cursor = (unw_cursor_t *)context;
|
||||
unw_set_reg(cursor, UNW_REG_IP, value);
|
||||
}
|
||||
|
||||
#endif // !_LIBUNWIND_ARM_EHABI
|
||||
#endif // !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__)
|
||||
|
@ -11,11 +11,17 @@
|
||||
|
||||
.text
|
||||
|
||||
#if !defined(__USING_SJLJ_EXCEPTIONS__)
|
||||
|
||||
#if defined(__i386__)
|
||||
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_x866jumptoEv)
|
||||
#
|
||||
# void libunwind::Registers_x86::jumpto()
|
||||
#
|
||||
#if defined(_WIN32)
|
||||
# On windows, the 'this' pointer is passed in ecx instead of on the stack
|
||||
movl %ecx, %eax
|
||||
#else
|
||||
# On entry:
|
||||
# + +
|
||||
# +-----------------------+
|
||||
@ -25,6 +31,7 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_x866jumptoEv)
|
||||
# +-----------------------+ <-- SP
|
||||
# + +
|
||||
movl 4(%esp), %eax
|
||||
#endif
|
||||
# set up eax and ret on new stack location
|
||||
movl 28(%eax), %edx # edx holds new stack pointer
|
||||
subl $8,%edx
|
||||
@ -58,7 +65,16 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind16Registers_x86_646jumptoEv)
|
||||
#
|
||||
# void libunwind::Registers_x86_64::jumpto()
|
||||
#
|
||||
#if defined(_WIN64)
|
||||
# On entry, thread_state pointer is in rcx; move it into rdi
|
||||
# to share restore code below. Since this routine restores and
|
||||
# overwrites all registers, we can use the same registers for
|
||||
# pointers and temporaries as on unix even though win64 normally
|
||||
# mustn't clobber some of them.
|
||||
movq %rcx, %rdi
|
||||
#else
|
||||
# On entry, thread_state pointer is in rdi
|
||||
#endif
|
||||
|
||||
movq 56(%rdi), %rax # rax holds new stack pointer
|
||||
subq $16, %rax
|
||||
@ -88,11 +104,295 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind16Registers_x86_646jumptoEv)
|
||||
# skip cs
|
||||
# skip fs
|
||||
# skip gs
|
||||
|
||||
#if defined(_WIN64)
|
||||
movdqu 176(%rdi),%xmm0
|
||||
movdqu 192(%rdi),%xmm1
|
||||
movdqu 208(%rdi),%xmm2
|
||||
movdqu 224(%rdi),%xmm3
|
||||
movdqu 240(%rdi),%xmm4
|
||||
movdqu 256(%rdi),%xmm5
|
||||
movdqu 272(%rdi),%xmm6
|
||||
movdqu 288(%rdi),%xmm7
|
||||
movdqu 304(%rdi),%xmm8
|
||||
movdqu 320(%rdi),%xmm9
|
||||
movdqu 336(%rdi),%xmm10
|
||||
movdqu 352(%rdi),%xmm11
|
||||
movdqu 368(%rdi),%xmm12
|
||||
movdqu 384(%rdi),%xmm13
|
||||
movdqu 400(%rdi),%xmm14
|
||||
movdqu 416(%rdi),%xmm15
|
||||
#endif
|
||||
movq 56(%rdi), %rsp # cut back rsp to new location
|
||||
pop %rdi # rdi was saved here earlier
|
||||
ret # rip was saved here
|
||||
|
||||
|
||||
#elif defined(__powerpc64__)
|
||||
|
||||
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind15Registers_ppc646jumptoEv)
|
||||
//
|
||||
// void libunwind::Registers_ppc64::jumpto()
|
||||
//
|
||||
// On entry:
|
||||
// thread_state pointer is in r3
|
||||
//
|
||||
|
||||
// load register (GPR)
|
||||
#define PPC64_LR(n) \
|
||||
ld %r##n, (8 * (n + 2))(%r3)
|
||||
|
||||
// restore integral registers
|
||||
// skip r0 for now
|
||||
// skip r1 for now
|
||||
PPC64_LR(2)
|
||||
// skip r3 for now
|
||||
// skip r4 for now
|
||||
// skip r5 for now
|
||||
PPC64_LR(6)
|
||||
PPC64_LR(7)
|
||||
PPC64_LR(8)
|
||||
PPC64_LR(9)
|
||||
PPC64_LR(10)
|
||||
PPC64_LR(11)
|
||||
PPC64_LR(12)
|
||||
PPC64_LR(13)
|
||||
PPC64_LR(14)
|
||||
PPC64_LR(15)
|
||||
PPC64_LR(16)
|
||||
PPC64_LR(17)
|
||||
PPC64_LR(18)
|
||||
PPC64_LR(19)
|
||||
PPC64_LR(20)
|
||||
PPC64_LR(21)
|
||||
PPC64_LR(22)
|
||||
PPC64_LR(23)
|
||||
PPC64_LR(24)
|
||||
PPC64_LR(25)
|
||||
PPC64_LR(26)
|
||||
PPC64_LR(27)
|
||||
PPC64_LR(28)
|
||||
PPC64_LR(29)
|
||||
PPC64_LR(30)
|
||||
PPC64_LR(31)
|
||||
|
||||
#ifdef PPC64_HAS_VMX
|
||||
|
||||
// restore VS registers
|
||||
// (note that this also restores floating point registers and V registers,
|
||||
// because part of VS is mapped to these registers)
|
||||
|
||||
addi %r4, %r3, PPC64_OFFS_FP
|
||||
|
||||
// load VS register
|
||||
#define PPC64_LVS(n) \
|
||||
lxvd2x %vs##n, 0, %r4 ;\
|
||||
addi %r4, %r4, 16
|
||||
|
||||
// restore the first 32 VS regs (and also all floating point regs)
|
||||
PPC64_LVS(0)
|
||||
PPC64_LVS(1)
|
||||
PPC64_LVS(2)
|
||||
PPC64_LVS(3)
|
||||
PPC64_LVS(4)
|
||||
PPC64_LVS(5)
|
||||
PPC64_LVS(6)
|
||||
PPC64_LVS(7)
|
||||
PPC64_LVS(8)
|
||||
PPC64_LVS(9)
|
||||
PPC64_LVS(10)
|
||||
PPC64_LVS(11)
|
||||
PPC64_LVS(12)
|
||||
PPC64_LVS(13)
|
||||
PPC64_LVS(14)
|
||||
PPC64_LVS(15)
|
||||
PPC64_LVS(16)
|
||||
PPC64_LVS(17)
|
||||
PPC64_LVS(18)
|
||||
PPC64_LVS(19)
|
||||
PPC64_LVS(20)
|
||||
PPC64_LVS(21)
|
||||
PPC64_LVS(22)
|
||||
PPC64_LVS(23)
|
||||
PPC64_LVS(24)
|
||||
PPC64_LVS(25)
|
||||
PPC64_LVS(26)
|
||||
PPC64_LVS(27)
|
||||
PPC64_LVS(28)
|
||||
PPC64_LVS(29)
|
||||
PPC64_LVS(30)
|
||||
PPC64_LVS(31)
|
||||
|
||||
// use VRSAVE to conditionally restore the remaining VS regs,
|
||||
// that are where the V regs are mapped
|
||||
|
||||
ld %r5, PPC64_OFFS_VRSAVE(%r3) // test VRsave
|
||||
cmpwi %r5, 0
|
||||
beq Lnovec
|
||||
|
||||
// conditionally load VS
|
||||
#define PPC64_CLVS_BOTTOM(n) \
|
||||
beq Ldone##n ;\
|
||||
addi %r4, %r3, PPC64_OFFS_FP + n * 16 ;\
|
||||
lxvd2x %vs##n, 0, %r4 ;\
|
||||
Ldone##n:
|
||||
|
||||
#define PPC64_CLVSl(n) \
|
||||
andis. %r0, %r5, (1<<(47-n)) ;\
|
||||
PPC64_CLVS_BOTTOM(n)
|
||||
|
||||
#define PPC64_CLVSh(n) \
|
||||
andi. %r0, %r5, (1<<(63-n)) ;\
|
||||
PPC64_CLVS_BOTTOM(n)
|
||||
|
||||
PPC64_CLVSl(32)
|
||||
PPC64_CLVSl(33)
|
||||
PPC64_CLVSl(34)
|
||||
PPC64_CLVSl(35)
|
||||
PPC64_CLVSl(36)
|
||||
PPC64_CLVSl(37)
|
||||
PPC64_CLVSl(38)
|
||||
PPC64_CLVSl(39)
|
||||
PPC64_CLVSl(40)
|
||||
PPC64_CLVSl(41)
|
||||
PPC64_CLVSl(42)
|
||||
PPC64_CLVSl(43)
|
||||
PPC64_CLVSl(44)
|
||||
PPC64_CLVSl(45)
|
||||
PPC64_CLVSl(46)
|
||||
PPC64_CLVSl(47)
|
||||
PPC64_CLVSh(48)
|
||||
PPC64_CLVSh(49)
|
||||
PPC64_CLVSh(50)
|
||||
PPC64_CLVSh(51)
|
||||
PPC64_CLVSh(52)
|
||||
PPC64_CLVSh(53)
|
||||
PPC64_CLVSh(54)
|
||||
PPC64_CLVSh(55)
|
||||
PPC64_CLVSh(56)
|
||||
PPC64_CLVSh(57)
|
||||
PPC64_CLVSh(58)
|
||||
PPC64_CLVSh(59)
|
||||
PPC64_CLVSh(60)
|
||||
PPC64_CLVSh(61)
|
||||
PPC64_CLVSh(62)
|
||||
PPC64_CLVSh(63)
|
||||
|
||||
#else
|
||||
|
||||
// load FP register
|
||||
#define PPC64_LF(n) \
|
||||
lfd %f##n, (PPC64_OFFS_FP + n * 16)(%r3)
|
||||
|
||||
// restore float registers
|
||||
PPC64_LF(0)
|
||||
PPC64_LF(1)
|
||||
PPC64_LF(2)
|
||||
PPC64_LF(3)
|
||||
PPC64_LF(4)
|
||||
PPC64_LF(5)
|
||||
PPC64_LF(6)
|
||||
PPC64_LF(7)
|
||||
PPC64_LF(8)
|
||||
PPC64_LF(9)
|
||||
PPC64_LF(10)
|
||||
PPC64_LF(11)
|
||||
PPC64_LF(12)
|
||||
PPC64_LF(13)
|
||||
PPC64_LF(14)
|
||||
PPC64_LF(15)
|
||||
PPC64_LF(16)
|
||||
PPC64_LF(17)
|
||||
PPC64_LF(18)
|
||||
PPC64_LF(19)
|
||||
PPC64_LF(20)
|
||||
PPC64_LF(21)
|
||||
PPC64_LF(22)
|
||||
PPC64_LF(23)
|
||||
PPC64_LF(24)
|
||||
PPC64_LF(25)
|
||||
PPC64_LF(26)
|
||||
PPC64_LF(27)
|
||||
PPC64_LF(28)
|
||||
PPC64_LF(29)
|
||||
PPC64_LF(30)
|
||||
PPC64_LF(31)
|
||||
|
||||
// restore vector registers if any are in use
|
||||
ld %r5, PPC64_OFFS_VRSAVE(%r3) // test VRsave
|
||||
cmpwi %r5, 0
|
||||
beq Lnovec
|
||||
|
||||
subi %r4, %r1, 16
|
||||
// r4 is now a 16-byte aligned pointer into the red zone
|
||||
// the _vectorScalarRegisters may not be 16-byte aligned
|
||||
// so copy via red zone temp buffer
|
||||
|
||||
#define PPC64_CLV_UNALIGNED_BOTTOM(n) \
|
||||
beq Ldone##n ;\
|
||||
ld %r0, (PPC64_OFFS_V + n * 16)(%r3) ;\
|
||||
std %r0, 0(%r4) ;\
|
||||
ld %r0, (PPC64_OFFS_V + n * 16 + 8)(%r3) ;\
|
||||
std %r0, 8(%r4) ;\
|
||||
lvx %v##n, 0, %r4 ;\
|
||||
Ldone ## n:
|
||||
|
||||
#define PPC64_CLV_UNALIGNEDl(n) \
|
||||
andis. %r0, %r5, (1<<(15-n)) ;\
|
||||
PPC64_CLV_UNALIGNED_BOTTOM(n)
|
||||
|
||||
#define PPC64_CLV_UNALIGNEDh(n) \
|
||||
andi. %r0, %r5, (1<<(31-n)) ;\
|
||||
PPC64_CLV_UNALIGNED_BOTTOM(n)
|
||||
|
||||
PPC64_CLV_UNALIGNEDl(0)
|
||||
PPC64_CLV_UNALIGNEDl(1)
|
||||
PPC64_CLV_UNALIGNEDl(2)
|
||||
PPC64_CLV_UNALIGNEDl(3)
|
||||
PPC64_CLV_UNALIGNEDl(4)
|
||||
PPC64_CLV_UNALIGNEDl(5)
|
||||
PPC64_CLV_UNALIGNEDl(6)
|
||||
PPC64_CLV_UNALIGNEDl(7)
|
||||
PPC64_CLV_UNALIGNEDl(8)
|
||||
PPC64_CLV_UNALIGNEDl(9)
|
||||
PPC64_CLV_UNALIGNEDl(10)
|
||||
PPC64_CLV_UNALIGNEDl(11)
|
||||
PPC64_CLV_UNALIGNEDl(12)
|
||||
PPC64_CLV_UNALIGNEDl(13)
|
||||
PPC64_CLV_UNALIGNEDl(14)
|
||||
PPC64_CLV_UNALIGNEDl(15)
|
||||
PPC64_CLV_UNALIGNEDh(16)
|
||||
PPC64_CLV_UNALIGNEDh(17)
|
||||
PPC64_CLV_UNALIGNEDh(18)
|
||||
PPC64_CLV_UNALIGNEDh(19)
|
||||
PPC64_CLV_UNALIGNEDh(20)
|
||||
PPC64_CLV_UNALIGNEDh(21)
|
||||
PPC64_CLV_UNALIGNEDh(22)
|
||||
PPC64_CLV_UNALIGNEDh(23)
|
||||
PPC64_CLV_UNALIGNEDh(24)
|
||||
PPC64_CLV_UNALIGNEDh(25)
|
||||
PPC64_CLV_UNALIGNEDh(26)
|
||||
PPC64_CLV_UNALIGNEDh(27)
|
||||
PPC64_CLV_UNALIGNEDh(28)
|
||||
PPC64_CLV_UNALIGNEDh(29)
|
||||
PPC64_CLV_UNALIGNEDh(30)
|
||||
PPC64_CLV_UNALIGNEDh(31)
|
||||
|
||||
#endif
|
||||
|
||||
Lnovec:
|
||||
ld %r0, PPC64_OFFS_CR(%r3)
|
||||
mtcr %r0
|
||||
ld %r0, PPC64_OFFS_SRR0(%r3)
|
||||
mtctr %r0
|
||||
|
||||
PPC64_LR(0)
|
||||
PPC64_LR(5)
|
||||
PPC64_LR(4)
|
||||
PPC64_LR(1)
|
||||
PPC64_LR(3)
|
||||
bctr
|
||||
|
||||
#elif defined(__ppc__)
|
||||
|
||||
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv)
|
||||
@ -322,9 +622,18 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind15Registers_arm646jumptoEv)
|
||||
@
|
||||
.p2align 2
|
||||
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm20restoreCoreAndJumpToEv)
|
||||
#if !defined(__ARM_ARCH_ISA_ARM)
|
||||
ldr r2, [r0, #52]
|
||||
ldr r3, [r0, #60]
|
||||
#if !defined(__ARM_ARCH_ISA_ARM) && __ARM_ARCH_ISA_THUMB == 1
|
||||
@ r8-r11: ldm into r1-r4, then mov to r8-r11
|
||||
adds r0, #0x20
|
||||
ldm r0!, {r1-r4}
|
||||
subs r0, #0x30
|
||||
mov r8, r1
|
||||
mov r9, r2
|
||||
mov r10, r3
|
||||
mov r11, r4
|
||||
@ r12 does not need loading, it it the intra-procedure-call scratch register
|
||||
ldr r2, [r0, #0x34]
|
||||
ldr r3, [r0, #0x3c]
|
||||
mov sp, r2
|
||||
mov lr, r3 @ restore pc into lr
|
||||
ldm r0, {r0-r7}
|
||||
@ -347,7 +656,9 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm20restoreCoreAndJu
|
||||
@ values pointer is in r0
|
||||
@
|
||||
.p2align 2
|
||||
#if defined(__ELF__)
|
||||
.fpu vfpv3-d16
|
||||
#endif
|
||||
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMDEPy)
|
||||
@ VFP and iwMMX instructions are only available when compiling with the flags
|
||||
@ that enable them. We do not want to do that in the library (because we do not
|
||||
@ -366,7 +677,9 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFL
|
||||
@ values pointer is in r0
|
||||
@
|
||||
.p2align 2
|
||||
#if defined(__ELF__)
|
||||
.fpu vfpv3-d16
|
||||
#endif
|
||||
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMXEPy)
|
||||
vldmia r0, {d0-d15} @ fldmiax is deprecated in ARMv7+ and now behaves like vldmia
|
||||
JMP(lr)
|
||||
@ -378,11 +691,15 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFL
|
||||
@ values pointer is in r0
|
||||
@
|
||||
.p2align 2
|
||||
#if defined(__ELF__)
|
||||
.fpu vfpv3
|
||||
#endif
|
||||
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreVFPv3EPy)
|
||||
vldmia r0, {d16-d31}
|
||||
JMP(lr)
|
||||
|
||||
#if defined(__ARM_WMMX)
|
||||
|
||||
@
|
||||
@ static void libunwind::Registers_arm::restoreiWMMX(unw_fpreg_t* values)
|
||||
@
|
||||
@ -390,8 +707,10 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreVFPv3EPy)
|
||||
@ values pointer is in r0
|
||||
@
|
||||
.p2align 2
|
||||
#if defined(__ELF__)
|
||||
.arch armv5te
|
||||
#endif
|
||||
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreiWMMXEPy)
|
||||
#if (!defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_6SM__)) || defined(__ARM_WMMX)
|
||||
ldcl p1, cr0, [r0], #8 @ wldrd wR0, [r0], #8
|
||||
ldcl p1, cr1, [r0], #8 @ wldrd wR1, [r0], #8
|
||||
ldcl p1, cr2, [r0], #8 @ wldrd wR2, [r0], #8
|
||||
@ -408,7 +727,6 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreiWMMXEPy)
|
||||
ldcl p1, cr13, [r0], #8 @ wldrd wR13, [r0], #8
|
||||
ldcl p1, cr14, [r0], #8 @ wldrd wR14, [r0], #8
|
||||
ldcl p1, cr15, [r0], #8 @ wldrd wR15, [r0], #8
|
||||
#endif
|
||||
JMP(lr)
|
||||
|
||||
@
|
||||
@ -418,15 +736,18 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreiWMMXEPy)
|
||||
@ values pointer is in r0
|
||||
@
|
||||
.p2align 2
|
||||
#if defined(__ELF__)
|
||||
.arch armv5te
|
||||
#endif
|
||||
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreiWMMXControlEPj)
|
||||
#if (!defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_6SM__)) || defined(__ARM_WMMX)
|
||||
ldc2 p1, cr8, [r0], #4 @ wldrw wCGR0, [r0], #4
|
||||
ldc2 p1, cr9, [r0], #4 @ wldrw wCGR1, [r0], #4
|
||||
ldc2 p1, cr10, [r0], #4 @ wldrw wCGR2, [r0], #4
|
||||
ldc2 p1, cr11, [r0], #4 @ wldrw wCGR3, [r0], #4
|
||||
#endif
|
||||
JMP(lr)
|
||||
|
||||
#endif
|
||||
|
||||
#elif defined(__or1k__)
|
||||
|
||||
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv)
|
||||
@ -437,7 +758,7 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv)
|
||||
# thread_state pointer is in r3
|
||||
#
|
||||
|
||||
# restore integral registerrs
|
||||
# restore integral registers
|
||||
l.lwz r0, 0(r3)
|
||||
l.lwz r1, 4(r3)
|
||||
l.lwz r2, 8(r3)
|
||||
@ -447,7 +768,7 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv)
|
||||
l.lwz r6, 24(r3)
|
||||
l.lwz r7, 28(r3)
|
||||
l.lwz r8, 32(r3)
|
||||
l.lwz r9, 36(r3)
|
||||
# skip r9
|
||||
l.lwz r10, 40(r3)
|
||||
l.lwz r11, 44(r3)
|
||||
l.lwz r12, 48(r3)
|
||||
@ -474,6 +795,8 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv)
|
||||
# at last, restore r3
|
||||
l.lwz r3, 12(r3)
|
||||
|
||||
# load new pc into ra
|
||||
l.lwz r9, 128(r3)
|
||||
# jump to pc
|
||||
l.jr r9
|
||||
l.nop
|
||||
@ -573,7 +896,7 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind18Registers_mips_o326jumptoEv)
|
||||
.set noreorder
|
||||
.set nomacro
|
||||
#ifdef __mips_hard_float
|
||||
#if __mips_fpr == 32
|
||||
#if __mips_fpr != 64
|
||||
ldc1 $f0, (4 * 36 + 8 * 0)($4)
|
||||
ldc1 $f2, (4 * 36 + 8 * 2)($4)
|
||||
ldc1 $f4, (4 * 36 + 8 * 4)($4)
|
||||
@ -758,7 +1081,31 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind21Registers_mips_newabi6jumptoEv)
|
||||
ld $4, (8 * 4)($4)
|
||||
.set pop
|
||||
|
||||
#elif defined(__sparc__)
|
||||
|
||||
//
|
||||
// void libunwind::Registers_sparc_o32::jumpto()
|
||||
//
|
||||
// On entry:
|
||||
// thread_state pointer is in o0
|
||||
//
|
||||
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind15Registers_sparc6jumptoEv)
|
||||
ta 3
|
||||
ldd [%o0 + 64], %l0
|
||||
ldd [%o0 + 72], %l2
|
||||
ldd [%o0 + 80], %l4
|
||||
ldd [%o0 + 88], %l6
|
||||
ldd [%o0 + 96], %i0
|
||||
ldd [%o0 + 104], %i2
|
||||
ldd [%o0 + 112], %i4
|
||||
ldd [%o0 + 120], %i6
|
||||
ld [%o0 + 60], %o7
|
||||
jmp %o7
|
||||
nop
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -11,6 +11,8 @@
|
||||
|
||||
.text
|
||||
|
||||
#if !defined(__USING_SJLJ_EXCEPTIONS__)
|
||||
|
||||
#if defined(__i386__)
|
||||
|
||||
#
|
||||
@ -61,29 +63,56 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
|
||||
# thread_state pointer is in rdi
|
||||
#
|
||||
DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
|
||||
movq %rax, (%rdi)
|
||||
movq %rbx, 8(%rdi)
|
||||
movq %rcx, 16(%rdi)
|
||||
movq %rdx, 24(%rdi)
|
||||
movq %rdi, 32(%rdi)
|
||||
movq %rsi, 40(%rdi)
|
||||
movq %rbp, 48(%rdi)
|
||||
movq %rsp, 56(%rdi)
|
||||
addq $8, 56(%rdi)
|
||||
movq %r8, 64(%rdi)
|
||||
movq %r9, 72(%rdi)
|
||||
movq %r10, 80(%rdi)
|
||||
movq %r11, 88(%rdi)
|
||||
movq %r12, 96(%rdi)
|
||||
movq %r13,104(%rdi)
|
||||
movq %r14,112(%rdi)
|
||||
movq %r15,120(%rdi)
|
||||
movq (%rsp),%rsi
|
||||
movq %rsi,128(%rdi) # store return address as rip
|
||||
#if defined(_WIN64)
|
||||
#define PTR %rcx
|
||||
#define TMP %rdx
|
||||
#else
|
||||
#define PTR %rdi
|
||||
#define TMP %rsi
|
||||
#endif
|
||||
|
||||
movq %rax, (PTR)
|
||||
movq %rbx, 8(PTR)
|
||||
movq %rcx, 16(PTR)
|
||||
movq %rdx, 24(PTR)
|
||||
movq %rdi, 32(PTR)
|
||||
movq %rsi, 40(PTR)
|
||||
movq %rbp, 48(PTR)
|
||||
movq %rsp, 56(PTR)
|
||||
addq $8, 56(PTR)
|
||||
movq %r8, 64(PTR)
|
||||
movq %r9, 72(PTR)
|
||||
movq %r10, 80(PTR)
|
||||
movq %r11, 88(PTR)
|
||||
movq %r12, 96(PTR)
|
||||
movq %r13,104(PTR)
|
||||
movq %r14,112(PTR)
|
||||
movq %r15,120(PTR)
|
||||
movq (%rsp),TMP
|
||||
movq TMP,128(PTR) # store return address as rip
|
||||
# skip rflags
|
||||
# skip cs
|
||||
# skip fs
|
||||
# skip gs
|
||||
|
||||
#if defined(_WIN64)
|
||||
movdqu %xmm0,176(PTR)
|
||||
movdqu %xmm1,192(PTR)
|
||||
movdqu %xmm2,208(PTR)
|
||||
movdqu %xmm3,224(PTR)
|
||||
movdqu %xmm4,240(PTR)
|
||||
movdqu %xmm5,256(PTR)
|
||||
movdqu %xmm6,272(PTR)
|
||||
movdqu %xmm7,288(PTR)
|
||||
movdqu %xmm8,304(PTR)
|
||||
movdqu %xmm9,320(PTR)
|
||||
movdqu %xmm10,336(PTR)
|
||||
movdqu %xmm11,352(PTR)
|
||||
movdqu %xmm12,368(PTR)
|
||||
movdqu %xmm13,384(PTR)
|
||||
movdqu %xmm14,400(PTR)
|
||||
movdqu %xmm15,416(PTR)
|
||||
#endif
|
||||
xorl %eax, %eax # return UNW_ESUCCESS
|
||||
ret
|
||||
|
||||
@ -139,7 +168,7 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
|
||||
mflo $8
|
||||
sw $8, (4 * 34)($4)
|
||||
#ifdef __mips_hard_float
|
||||
#if __mips_fpr == 32
|
||||
#if __mips_fpr != 64
|
||||
sdc1 $f0, (4 * 36 + 8 * 0)($4)
|
||||
sdc1 $f2, (4 * 36 + 8 * 2)($4)
|
||||
sdc1 $f4, (4 * 36 + 8 * 4)($4)
|
||||
@ -295,6 +324,237 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
|
||||
DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
|
||||
teq $0, $0
|
||||
|
||||
#elif defined(__powerpc64__)
|
||||
|
||||
//
|
||||
// extern int unw_getcontext(unw_context_t* thread_state)
|
||||
//
|
||||
// On entry:
|
||||
// thread_state pointer is in r3
|
||||
//
|
||||
DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
|
||||
|
||||
// store register (GPR)
|
||||
#define PPC64_STR(n) \
|
||||
std %r##n, (8 * (n + 2))(%r3)
|
||||
|
||||
// save GPRs
|
||||
PPC64_STR(0)
|
||||
mflr %r0
|
||||
std %r0, PPC64_OFFS_SRR0(%r3) // store lr as ssr0
|
||||
PPC64_STR(1)
|
||||
PPC64_STR(2)
|
||||
PPC64_STR(3)
|
||||
PPC64_STR(4)
|
||||
PPC64_STR(5)
|
||||
PPC64_STR(6)
|
||||
PPC64_STR(7)
|
||||
PPC64_STR(8)
|
||||
PPC64_STR(9)
|
||||
PPC64_STR(10)
|
||||
PPC64_STR(11)
|
||||
PPC64_STR(12)
|
||||
PPC64_STR(13)
|
||||
PPC64_STR(14)
|
||||
PPC64_STR(15)
|
||||
PPC64_STR(16)
|
||||
PPC64_STR(17)
|
||||
PPC64_STR(18)
|
||||
PPC64_STR(19)
|
||||
PPC64_STR(20)
|
||||
PPC64_STR(21)
|
||||
PPC64_STR(22)
|
||||
PPC64_STR(23)
|
||||
PPC64_STR(24)
|
||||
PPC64_STR(25)
|
||||
PPC64_STR(26)
|
||||
PPC64_STR(27)
|
||||
PPC64_STR(28)
|
||||
PPC64_STR(29)
|
||||
PPC64_STR(30)
|
||||
PPC64_STR(31)
|
||||
|
||||
mfcr %r0
|
||||
std %r0, PPC64_OFFS_CR(%r3)
|
||||
mfxer %r0
|
||||
std %r0, PPC64_OFFS_XER(%r3)
|
||||
mflr %r0
|
||||
std %r0, PPC64_OFFS_LR(%r3)
|
||||
mfctr %r0
|
||||
std %r0, PPC64_OFFS_CTR(%r3)
|
||||
mfvrsave %r0
|
||||
std %r0, PPC64_OFFS_VRSAVE(%r3)
|
||||
|
||||
#ifdef PPC64_HAS_VMX
|
||||
// save VS registers
|
||||
// (note that this also saves floating point registers and V registers,
|
||||
// because part of VS is mapped to these registers)
|
||||
|
||||
addi %r4, %r3, PPC64_OFFS_FP
|
||||
|
||||
// store VS register
|
||||
#define PPC64_STVS(n) \
|
||||
stxvd2x %vs##n, 0, %r4 ;\
|
||||
addi %r4, %r4, 16
|
||||
|
||||
PPC64_STVS(0)
|
||||
PPC64_STVS(1)
|
||||
PPC64_STVS(2)
|
||||
PPC64_STVS(3)
|
||||
PPC64_STVS(4)
|
||||
PPC64_STVS(5)
|
||||
PPC64_STVS(6)
|
||||
PPC64_STVS(7)
|
||||
PPC64_STVS(8)
|
||||
PPC64_STVS(9)
|
||||
PPC64_STVS(10)
|
||||
PPC64_STVS(11)
|
||||
PPC64_STVS(12)
|
||||
PPC64_STVS(13)
|
||||
PPC64_STVS(14)
|
||||
PPC64_STVS(15)
|
||||
PPC64_STVS(16)
|
||||
PPC64_STVS(17)
|
||||
PPC64_STVS(18)
|
||||
PPC64_STVS(19)
|
||||
PPC64_STVS(20)
|
||||
PPC64_STVS(21)
|
||||
PPC64_STVS(22)
|
||||
PPC64_STVS(23)
|
||||
PPC64_STVS(24)
|
||||
PPC64_STVS(25)
|
||||
PPC64_STVS(26)
|
||||
PPC64_STVS(27)
|
||||
PPC64_STVS(28)
|
||||
PPC64_STVS(29)
|
||||
PPC64_STVS(30)
|
||||
PPC64_STVS(31)
|
||||
PPC64_STVS(32)
|
||||
PPC64_STVS(33)
|
||||
PPC64_STVS(34)
|
||||
PPC64_STVS(35)
|
||||
PPC64_STVS(36)
|
||||
PPC64_STVS(37)
|
||||
PPC64_STVS(38)
|
||||
PPC64_STVS(39)
|
||||
PPC64_STVS(40)
|
||||
PPC64_STVS(41)
|
||||
PPC64_STVS(42)
|
||||
PPC64_STVS(43)
|
||||
PPC64_STVS(44)
|
||||
PPC64_STVS(45)
|
||||
PPC64_STVS(46)
|
||||
PPC64_STVS(47)
|
||||
PPC64_STVS(48)
|
||||
PPC64_STVS(49)
|
||||
PPC64_STVS(50)
|
||||
PPC64_STVS(51)
|
||||
PPC64_STVS(52)
|
||||
PPC64_STVS(53)
|
||||
PPC64_STVS(54)
|
||||
PPC64_STVS(55)
|
||||
PPC64_STVS(56)
|
||||
PPC64_STVS(57)
|
||||
PPC64_STVS(58)
|
||||
PPC64_STVS(59)
|
||||
PPC64_STVS(60)
|
||||
PPC64_STVS(61)
|
||||
PPC64_STVS(62)
|
||||
PPC64_STVS(63)
|
||||
|
||||
#else
|
||||
|
||||
// store FP register
|
||||
#define PPC64_STF(n) \
|
||||
stfd %f##n, (PPC64_OFFS_FP + n * 16)(%r3)
|
||||
|
||||
// save float registers
|
||||
PPC64_STF(0)
|
||||
PPC64_STF(1)
|
||||
PPC64_STF(2)
|
||||
PPC64_STF(3)
|
||||
PPC64_STF(4)
|
||||
PPC64_STF(5)
|
||||
PPC64_STF(6)
|
||||
PPC64_STF(7)
|
||||
PPC64_STF(8)
|
||||
PPC64_STF(9)
|
||||
PPC64_STF(10)
|
||||
PPC64_STF(11)
|
||||
PPC64_STF(12)
|
||||
PPC64_STF(13)
|
||||
PPC64_STF(14)
|
||||
PPC64_STF(15)
|
||||
PPC64_STF(16)
|
||||
PPC64_STF(17)
|
||||
PPC64_STF(18)
|
||||
PPC64_STF(19)
|
||||
PPC64_STF(20)
|
||||
PPC64_STF(21)
|
||||
PPC64_STF(22)
|
||||
PPC64_STF(23)
|
||||
PPC64_STF(24)
|
||||
PPC64_STF(25)
|
||||
PPC64_STF(26)
|
||||
PPC64_STF(27)
|
||||
PPC64_STF(28)
|
||||
PPC64_STF(29)
|
||||
PPC64_STF(30)
|
||||
PPC64_STF(31)
|
||||
|
||||
// save vector registers
|
||||
|
||||
// Use 16-bytes below the stack pointer as an
|
||||
// aligned buffer to save each vector register.
|
||||
// Note that the stack pointer is always 16-byte aligned.
|
||||
subi %r4, %r1, 16
|
||||
|
||||
#define PPC64_STV_UNALIGNED(n) \
|
||||
stvx %v##n, 0, %r4 ;\
|
||||
ld %r5, 0(%r4) ;\
|
||||
std %r5, (PPC64_OFFS_V + n * 16)(%r3) ;\
|
||||
ld %r5, 8(%r4) ;\
|
||||
std %r5, (PPC64_OFFS_V + n * 16 + 8)(%r3)
|
||||
|
||||
PPC64_STV_UNALIGNED(0)
|
||||
PPC64_STV_UNALIGNED(1)
|
||||
PPC64_STV_UNALIGNED(2)
|
||||
PPC64_STV_UNALIGNED(3)
|
||||
PPC64_STV_UNALIGNED(4)
|
||||
PPC64_STV_UNALIGNED(5)
|
||||
PPC64_STV_UNALIGNED(6)
|
||||
PPC64_STV_UNALIGNED(7)
|
||||
PPC64_STV_UNALIGNED(8)
|
||||
PPC64_STV_UNALIGNED(9)
|
||||
PPC64_STV_UNALIGNED(10)
|
||||
PPC64_STV_UNALIGNED(11)
|
||||
PPC64_STV_UNALIGNED(12)
|
||||
PPC64_STV_UNALIGNED(13)
|
||||
PPC64_STV_UNALIGNED(14)
|
||||
PPC64_STV_UNALIGNED(15)
|
||||
PPC64_STV_UNALIGNED(16)
|
||||
PPC64_STV_UNALIGNED(17)
|
||||
PPC64_STV_UNALIGNED(18)
|
||||
PPC64_STV_UNALIGNED(19)
|
||||
PPC64_STV_UNALIGNED(20)
|
||||
PPC64_STV_UNALIGNED(21)
|
||||
PPC64_STV_UNALIGNED(22)
|
||||
PPC64_STV_UNALIGNED(23)
|
||||
PPC64_STV_UNALIGNED(24)
|
||||
PPC64_STV_UNALIGNED(25)
|
||||
PPC64_STV_UNALIGNED(26)
|
||||
PPC64_STV_UNALIGNED(27)
|
||||
PPC64_STV_UNALIGNED(28)
|
||||
PPC64_STV_UNALIGNED(29)
|
||||
PPC64_STV_UNALIGNED(30)
|
||||
PPC64_STV_UNALIGNED(31)
|
||||
|
||||
#endif
|
||||
|
||||
li %r3, 0 // return UNW_ESUCCESS
|
||||
blr
|
||||
|
||||
|
||||
#elif defined(__ppc__)
|
||||
|
||||
;
|
||||
@ -508,13 +768,24 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
|
||||
@
|
||||
.p2align 2
|
||||
DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
|
||||
#if !defined(__ARM_ARCH_ISA_ARM)
|
||||
stm r0, {r0-r7}
|
||||
#if !defined(__ARM_ARCH_ISA_ARM) && __ARM_ARCH_ISA_THUMB == 1
|
||||
stm r0!, {r0-r7}
|
||||
mov r1, r8
|
||||
mov r2, r9
|
||||
mov r3, r10
|
||||
stm r0!, {r1-r3}
|
||||
mov r1, r11
|
||||
mov r2, sp
|
||||
mov r3, lr
|
||||
str r2, [r0, #52]
|
||||
str r3, [r0, #56]
|
||||
str r3, [r0, #60] @ store return address as pc
|
||||
str r1, [r0, #0] @ r11
|
||||
@ r12 does not need storing, it it the intra-procedure-call scratch register
|
||||
str r2, [r0, #8] @ sp
|
||||
str r3, [r0, #12] @ lr
|
||||
str r3, [r0, #16] @ store return address as pc
|
||||
@ T1 does not have a non-cpsr-clobbering register-zeroing instruction.
|
||||
@ It is safe to use here though because we are about to return, and cpsr is
|
||||
@ not expected to be preserved.
|
||||
movs r0, #0 @ return UNW_ESUCCESS
|
||||
#else
|
||||
@ 32bit thumb-2 restrictions for stm:
|
||||
@ . the sp (r13) cannot be in the list
|
||||
@ -523,13 +794,6 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
|
||||
str sp, [r0, #52]
|
||||
str lr, [r0, #56]
|
||||
str lr, [r0, #60] @ store return address as pc
|
||||
#endif
|
||||
#if __ARM_ARCH_ISA_THUMB == 1
|
||||
@ T1 does not have a non-cpsr-clobbering register-zeroing instruction.
|
||||
@ It is safe to use here though because we are about to return, and cpsr is
|
||||
@ not expected to be preserved.
|
||||
movs r0, #0 @ return UNW_ESUCCESS
|
||||
#else
|
||||
mov r0, #0 @ return UNW_ESUCCESS
|
||||
#endif
|
||||
JMP(lr)
|
||||
@ -541,7 +805,9 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
|
||||
@ values pointer is in r0
|
||||
@
|
||||
.p2align 2
|
||||
#if defined(__ELF__)
|
||||
.fpu vfpv3-d16
|
||||
#endif
|
||||
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMDEPy)
|
||||
vstmia r0, {d0-d15}
|
||||
JMP(lr)
|
||||
@ -553,7 +819,9 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMD
|
||||
@ values pointer is in r0
|
||||
@
|
||||
.p2align 2
|
||||
#if defined(__ELF__)
|
||||
.fpu vfpv3-d16
|
||||
#endif
|
||||
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMXEPy)
|
||||
vstmia r0, {d0-d15} @ fstmiax is deprecated in ARMv7+ and now behaves like vstmia
|
||||
JMP(lr)
|
||||
@ -565,7 +833,9 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMX
|
||||
@ values pointer is in r0
|
||||
@
|
||||
.p2align 2
|
||||
#if defined(__ELF__)
|
||||
.fpu vfpv3
|
||||
#endif
|
||||
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveVFPv3EPy)
|
||||
@ VFP and iwMMX instructions are only available when compiling with the flags
|
||||
@ that enable them. We do not want to do that in the library (because we do not
|
||||
@ -577,6 +847,8 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveVFPv3EPy)
|
||||
vstmia r0, {d16-d31}
|
||||
JMP(lr)
|
||||
|
||||
#if defined(_LIBUNWIND_ARM_WMMX)
|
||||
|
||||
@
|
||||
@ static void libunwind::Registers_arm::saveiWMMX(unw_fpreg_t* values)
|
||||
@
|
||||
@ -584,8 +856,10 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveVFPv3EPy)
|
||||
@ values pointer is in r0
|
||||
@
|
||||
.p2align 2
|
||||
#if defined(__ELF__)
|
||||
.arch armv5te
|
||||
#endif
|
||||
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveiWMMXEPy)
|
||||
#if (!defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_6SM__)) || defined(__ARM_WMMX)
|
||||
stcl p1, cr0, [r0], #8 @ wstrd wR0, [r0], #8
|
||||
stcl p1, cr1, [r0], #8 @ wstrd wR1, [r0], #8
|
||||
stcl p1, cr2, [r0], #8 @ wstrd wR2, [r0], #8
|
||||
@ -602,7 +876,6 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveiWMMXEPy)
|
||||
stcl p1, cr13, [r0], #8 @ wstrd wR13, [r0], #8
|
||||
stcl p1, cr14, [r0], #8 @ wstrd wR14, [r0], #8
|
||||
stcl p1, cr15, [r0], #8 @ wstrd wR15, [r0], #8
|
||||
#endif
|
||||
JMP(lr)
|
||||
|
||||
@
|
||||
@ -612,15 +885,18 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveiWMMXEPy)
|
||||
@ values pointer is in r0
|
||||
@
|
||||
.p2align 2
|
||||
#if defined(__ELF__)
|
||||
.arch armv5te
|
||||
#endif
|
||||
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveiWMMXControlEPj)
|
||||
#if (!defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_6SM__)) || defined(__ARM_WMMX)
|
||||
stc2 p1, cr8, [r0], #4 @ wstrw wCGR0, [r0], #4
|
||||
stc2 p1, cr9, [r0], #4 @ wstrw wCGR1, [r0], #4
|
||||
stc2 p1, cr10, [r0], #4 @ wstrw wCGR2, [r0], #4
|
||||
stc2 p1, cr11, [r0], #4 @ wstrw wCGR3, [r0], #4
|
||||
#endif
|
||||
JMP(lr)
|
||||
|
||||
#endif
|
||||
|
||||
#elif defined(__or1k__)
|
||||
|
||||
#
|
||||
@ -662,6 +938,10 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
|
||||
l.sw 116(r3), r29
|
||||
l.sw 120(r3), r30
|
||||
l.sw 124(r3), r31
|
||||
# store ra to pc
|
||||
l.sw 128(r3), r9
|
||||
# zero epcr
|
||||
l.sw 132(r3), r0
|
||||
|
||||
#elif defined(__riscv)
|
||||
|
||||
@ -742,7 +1022,37 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
|
||||
|
||||
li a0, 0 // return UNW_ESUCCESS
|
||||
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 /* !defined(__USING_SJLJ_EXCEPTIONS__) */
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -9,8 +9,8 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "config.h"
|
||||
#include "AddressSpace.hpp"
|
||||
#include "DwarfParser.hpp"
|
||||
#include "unwind_ext.h"
|
||||
|
||||
|
||||
// private keymgr stuff
|
||||
@ -76,7 +76,7 @@ struct libgcc_object_info {
|
||||
#endif
|
||||
|
||||
|
||||
#if _LIBUNWIND_BUILD_ZERO_COST_APIS
|
||||
#if defined(_LIBUNWIND_BUILD_ZERO_COST_APIS)
|
||||
|
||||
//
|
||||
// symbols in libSystem.dylib in 10.6 and later, but are in libgcc_s.dylib in
|
||||
@ -115,12 +115,12 @@ NEVER_HERE(__register_frame_table)
|
||||
NEVER_HERE(__deregister_frame_info)
|
||||
NEVER_HERE(__deregister_frame_info_bases)
|
||||
|
||||
#endif // _LIBUNWIND_BUILD_ZERO_COST_APIS
|
||||
#endif // defined(_LIBUNWIND_BUILD_ZERO_COST_APIS)
|
||||
|
||||
|
||||
|
||||
|
||||
#if _LIBUNWIND_BUILD_SJLJ_APIS
|
||||
#if defined(_LIBUNWIND_BUILD_SJLJ_APIS)
|
||||
//
|
||||
// symbols in libSystem.dylib in iOS 5.0 and later, but are in libgcc_s.dylib in
|
||||
// earlier versions
|
||||
@ -140,7 +140,7 @@ NOT_HERE_BEFORE_5_0(_Unwind_SjLj_RaiseException)
|
||||
NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Resume_or_Rethrow)
|
||||
NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Unregister)
|
||||
|
||||
#endif // _LIBUNWIND_BUILD_SJLJ_APIS
|
||||
#endif // defined(_LIBUNWIND_BUILD_SJLJ_APIS)
|
||||
|
||||
|
||||
namespace libunwind {
|
||||
@ -182,24 +182,3 @@ bool checkKeyMgrRegisteredFDEs(uintptr_t pc, void *&fde) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
#if !defined(FOR_DYLD) && _LIBUNWIND_BUILD_SJLJ_APIS
|
||||
|
||||
#include <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
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -16,7 +16,20 @@
|
||||
#ifndef UNWIND_ASSEMBLY_H
|
||||
#define UNWIND_ASSEMBLY_H
|
||||
|
||||
#if defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__)
|
||||
#if defined(__powerpc64__)
|
||||
#define SEPARATOR ;
|
||||
#define PPC64_OFFS_SRR0 0
|
||||
#define PPC64_OFFS_CR 272
|
||||
#define PPC64_OFFS_XER 280
|
||||
#define PPC64_OFFS_LR 288
|
||||
#define PPC64_OFFS_CTR 296
|
||||
#define PPC64_OFFS_VRSAVE 304
|
||||
#define PPC64_OFFS_FP 312
|
||||
#define PPC64_OFFS_V 824
|
||||
#ifdef _ARCH_PWR8
|
||||
#define PPC64_HAS_VMX
|
||||
#endif
|
||||
#elif defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__)
|
||||
#define SEPARATOR @
|
||||
#elif defined(__arm64__)
|
||||
#define SEPARATOR %%
|
||||
@ -24,12 +37,6 @@
|
||||
#define SEPARATOR ;
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#define HIDDEN_DIRECTIVE .private_extern
|
||||
#else
|
||||
#define HIDDEN_DIRECTIVE .hidden
|
||||
#endif
|
||||
|
||||
#define GLUE2(a, b) a ## b
|
||||
#define GLUE(a, b) GLUE2(a, b)
|
||||
#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
|
||||
@ -37,6 +44,8 @@
|
||||
#if defined(__APPLE__)
|
||||
|
||||
#define SYMBOL_IS_FUNC(name)
|
||||
#define EXPORT_SYMBOL(name)
|
||||
#define HIDDEN_SYMBOL(name) .private_extern name
|
||||
#define NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
#elif defined(__ELF__)
|
||||
@ -46,33 +55,53 @@
|
||||
#else
|
||||
#define SYMBOL_IS_FUNC(name) .type name,@function
|
||||
#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
|
||||
#else
|
||||
#define NO_EXEC_STACK_DIRECTIVE
|
||||
#endif
|
||||
|
||||
#else
|
||||
#elif defined(_WIN32)
|
||||
|
||||
#define SYMBOL_IS_FUNC(name) \
|
||||
.def name SEPARATOR \
|
||||
.scl 2 SEPARATOR \
|
||||
.type 32 SEPARATOR \
|
||||
.endef
|
||||
#define EXPORT_SYMBOL2(name) \
|
||||
.section .drectve,"yn" SEPARATOR \
|
||||
.ascii "-export:", #name, "\0" SEPARATOR \
|
||||
.text
|
||||
#if defined(_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS)
|
||||
#define EXPORT_SYMBOL(name)
|
||||
#else
|
||||
#define EXPORT_SYMBOL(name) EXPORT_SYMBOL2(name)
|
||||
#endif
|
||||
#define HIDDEN_SYMBOL(name)
|
||||
|
||||
#define NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
#elif defined(__sparc__)
|
||||
|
||||
#else
|
||||
|
||||
#error Unsupported target
|
||||
|
||||
#endif
|
||||
|
||||
#define DEFINE_LIBUNWIND_FUNCTION(name) \
|
||||
.globl SYMBOL_NAME(name) SEPARATOR \
|
||||
EXPORT_SYMBOL(name) SEPARATOR \
|
||||
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
|
||||
SYMBOL_NAME(name):
|
||||
|
||||
#define DEFINE_LIBUNWIND_PRIVATE_FUNCTION(name) \
|
||||
.globl SYMBOL_NAME(name) SEPARATOR \
|
||||
HIDDEN_DIRECTIVE SYMBOL_NAME(name) SEPARATOR \
|
||||
HIDDEN_SYMBOL(SYMBOL_NAME(name)) SEPARATOR \
|
||||
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
|
||||
SYMBOL_NAME(name):
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Define static_assert() unless already defined by compiler.
|
||||
@ -31,52 +32,66 @@
|
||||
// Platform specific configuration defines.
|
||||
#ifdef __APPLE__
|
||||
#if defined(FOR_DYLD)
|
||||
#define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1
|
||||
#define _LIBUNWIND_SUPPORT_DWARF_UNWIND 0
|
||||
#define _LIBUNWIND_SUPPORT_DWARF_INDEX 0
|
||||
#define _LIBUNWIND_SUPPORT_COMPACT_UNWIND
|
||||
#else
|
||||
#define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1
|
||||
#define _LIBUNWIND_SUPPORT_COMPACT_UNWIND
|
||||
#define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
|
||||
#define _LIBUNWIND_SUPPORT_DWARF_INDEX 0
|
||||
#endif
|
||||
#elif defined(_WIN32)
|
||||
#ifdef __SEH__
|
||||
#define _LIBUNWIND_SUPPORT_SEH_UNWIND 1
|
||||
#else
|
||||
#define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
|
||||
#endif
|
||||
#else
|
||||
#if defined(__ARM_DWARF_EH__) || !defined(__arm__)
|
||||
#define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 0
|
||||
#define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
|
||||
#define _LIBUNWIND_SUPPORT_DWARF_INDEX 1
|
||||
#else
|
||||
#define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 0
|
||||
#define _LIBUNWIND_SUPPORT_DWARF_UNWIND 0
|
||||
#define _LIBUNWIND_SUPPORT_DWARF_INDEX 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// FIXME: these macros are not correct for COFF targets
|
||||
#define _LIBUNWIND_EXPORT __attribute__((visibility("default")))
|
||||
#define _LIBUNWIND_HIDDEN __attribute__((visibility("hidden")))
|
||||
|
||||
#if (defined(__APPLE__) && defined(__arm__)) || defined(__USING_SJLJ_EXCEPTIONS__)
|
||||
#define _LIBUNWIND_BUILD_SJLJ_APIS 1
|
||||
#if defined(_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS)
|
||||
#define _LIBUNWIND_EXPORT
|
||||
#define _LIBUNWIND_HIDDEN
|
||||
#else
|
||||
#define _LIBUNWIND_BUILD_SJLJ_APIS 0
|
||||
#if !defined(__ELF__) && !defined(__MACH__)
|
||||
#define _LIBUNWIND_EXPORT __declspec(dllexport)
|
||||
#define _LIBUNWIND_HIDDEN
|
||||
#else
|
||||
#define _LIBUNWIND_EXPORT __attribute__((visibility("default")))
|
||||
#define _LIBUNWIND_HIDDEN __attribute__((visibility("hidden")))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
#define _LIBUNWIND_SUPPORT_FRAME_APIS 1
|
||||
#else
|
||||
#define _LIBUNWIND_SUPPORT_FRAME_APIS 0
|
||||
#if (defined(__APPLE__) && defined(__arm__)) || defined(__USING_SJLJ_EXCEPTIONS__)
|
||||
#define _LIBUNWIND_BUILD_SJLJ_APIS
|
||||
#endif
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__ppc64__) || defined(__powerpc64__)
|
||||
#define _LIBUNWIND_SUPPORT_FRAME_APIS
|
||||
#endif
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__) || \
|
||||
defined(__ppc__) || defined(__ppc64__) || defined(__powerpc64__) || \
|
||||
(!defined(__APPLE__) && defined(__arm__)) || \
|
||||
(defined(__arm64__) || defined(__aarch64__)) || \
|
||||
(defined(__mips__)) || \
|
||||
defined(__mips__) || \
|
||||
defined(__riscv)
|
||||
#define _LIBUNWIND_BUILD_ZERO_COST_APIS 1
|
||||
#else
|
||||
#define _LIBUNWIND_BUILD_ZERO_COST_APIS 0
|
||||
#if !defined(_LIBUNWIND_BUILD_SJLJ_APIS)
|
||||
#define _LIBUNWIND_BUILD_ZERO_COST_APIS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__powerpc64__) && defined(_ARCH_PWR8)
|
||||
#define PPC64_HAS_VMX
|
||||
#endif
|
||||
|
||||
#if defined(NDEBUG) && defined(_LIBUNWIND_IS_BAREMETAL)
|
||||
#define _LIBUNWIND_ABORT(msg) \
|
||||
do { \
|
||||
abort(); \
|
||||
} while (0)
|
||||
#else
|
||||
#define _LIBUNWIND_ABORT(msg) \
|
||||
do { \
|
||||
fprintf(stderr, "libunwind: %s %s:%d - %s\n", __func__, __FILE__, \
|
||||
@ -84,40 +99,65 @@
|
||||
fflush(stderr); \
|
||||
abort(); \
|
||||
} 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
|
||||
#ifdef NDEBUG
|
||||
#define _LIBUNWIND_DEBUG_LOG(msg, ...)
|
||||
#define _LIBUNWIND_TRACE_API(msg, ...)
|
||||
#define _LIBUNWIND_TRACING_UNWINDING 0
|
||||
#define _LIBUNWIND_TRACING_UNWINDING (0)
|
||||
#define _LIBUNWIND_TRACING_DWARF (0)
|
||||
#define _LIBUNWIND_TRACE_UNWINDING(msg, ...)
|
||||
#define _LIBUNWIND_LOG_NON_ZERO(x) x
|
||||
#define _LIBUNWIND_TRACE_DWARF(...)
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
extern bool logAPIs();
|
||||
extern bool logUnwinding();
|
||||
extern bool logDWARF();
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#define _LIBUNWIND_DEBUG_LOG(msg, ...) _LIBUNWIND_LOG(msg, __VA_ARGS__)
|
||||
#define _LIBUNWIND_LOG_NON_ZERO(x) \
|
||||
do { \
|
||||
int _err = x; \
|
||||
if ( _err != 0 ) \
|
||||
_LIBUNWIND_LOG("" #x "=%d in %s", _err, __FUNCTION__); \
|
||||
} while (0)
|
||||
#define _LIBUNWIND_TRACE_API(msg, ...) \
|
||||
do { \
|
||||
if ( logAPIs() ) _LIBUNWIND_LOG(msg, __VA_ARGS__); \
|
||||
} while(0)
|
||||
#define _LIBUNWIND_TRACE_UNWINDING(msg, ...) \
|
||||
do { \
|
||||
if ( logUnwinding() ) _LIBUNWIND_LOG(msg, __VA_ARGS__); \
|
||||
} while(0)
|
||||
#define _LIBUNWIND_TRACE_API(msg, ...) \
|
||||
do { \
|
||||
if (logAPIs()) \
|
||||
_LIBUNWIND_LOG(msg, __VA_ARGS__); \
|
||||
} while (0)
|
||||
#define _LIBUNWIND_TRACING_UNWINDING logUnwinding()
|
||||
#define _LIBUNWIND_TRACING_DWARF logDWARF()
|
||||
#define _LIBUNWIND_TRACE_UNWINDING(msg, ...) \
|
||||
do { \
|
||||
if (logUnwinding()) \
|
||||
_LIBUNWIND_LOG(msg, __VA_ARGS__); \
|
||||
} while (0)
|
||||
#define _LIBUNWIND_TRACE_DWARF(...) \
|
||||
do { \
|
||||
if (logDWARF()) \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -126,7 +166,7 @@
|
||||
#if defined(_LIBUNWIND_IS_NATIVE_ONLY)
|
||||
# define COMP_OP ==
|
||||
#else
|
||||
# define COMP_OP <
|
||||
# define COMP_OP <=
|
||||
#endif
|
||||
template <typename _Type, typename _Mem>
|
||||
struct check_fit {
|
||||
|
@ -49,7 +49,10 @@ enum {
|
||||
// GNU extensions
|
||||
DW_CFA_GNU_window_save = 0x2D,
|
||||
DW_CFA_GNU_args_size = 0x2E,
|
||||
DW_CFA_GNU_negative_offset_extended = 0x2F
|
||||
DW_CFA_GNU_negative_offset_extended = 0x2F,
|
||||
|
||||
// AARCH64 extensions
|
||||
DW_CFA_AARCH64_negate_ra_state = 0x2D
|
||||
};
|
||||
|
||||
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
#if !defined(__USING_SJLJ_EXCEPTIONS__)
|
||||
#include "AddressSpace.hpp"
|
||||
#include "UnwindCursor.hpp"
|
||||
|
||||
using namespace libunwind;
|
||||
@ -49,11 +51,13 @@ _LIBUNWIND_EXPORT int unw_init_local(unw_cursor_t *cursor,
|
||||
# define REGISTER_KIND Registers_x86
|
||||
#elif defined(__x86_64__)
|
||||
# define REGISTER_KIND Registers_x86_64
|
||||
#elif defined(__powerpc64__)
|
||||
# define REGISTER_KIND Registers_ppc64
|
||||
#elif defined(__ppc__)
|
||||
# define REGISTER_KIND Registers_ppc
|
||||
#elif defined(__aarch64__)
|
||||
# define REGISTER_KIND Registers_arm64
|
||||
#elif _LIBUNWIND_ARM_EHABI
|
||||
#elif defined(__arm__)
|
||||
# define REGISTER_KIND Registers_arm
|
||||
#elif defined(__or1k__)
|
||||
# define REGISTER_KIND Registers_or1k
|
||||
@ -65,6 +69,8 @@ _LIBUNWIND_EXPORT int unw_init_local(unw_cursor_t *cursor,
|
||||
# define REGISTER_KIND Registers_mips_newabi
|
||||
#elif defined(__mips__)
|
||||
# warning The MIPS architecture is not supported with this ABI and environment!
|
||||
#elif defined(__sparc__)
|
||||
# define REGISTER_KIND Registers_sparc
|
||||
#else
|
||||
# error Architecture not supported
|
||||
#endif
|
||||
@ -91,18 +97,18 @@ _LIBUNWIND_EXPORT int unw_init_remote_thread(unw_cursor_t *cursor,
|
||||
switch (as->cpuType) {
|
||||
case CPU_TYPE_I386:
|
||||
new ((void *)cursor)
|
||||
UnwindCursor<OtherAddressSpace<Pointer32<LittleEndian> >,
|
||||
UnwindCursor<RemoteAddressSpace<Pointer32<LittleEndian>>,
|
||||
Registers_x86>(((unw_addr_space_i386 *)as)->oas, arg);
|
||||
break;
|
||||
case CPU_TYPE_X86_64:
|
||||
new ((void *)cursor) UnwindCursor<
|
||||
OtherAddressSpace<Pointer64<LittleEndian> >, Registers_x86_64>(
|
||||
((unw_addr_space_x86_64 *)as)->oas, arg);
|
||||
new ((void *)cursor)
|
||||
UnwindCursor<RemoteAddressSpace<Pointer64<LittleEndian>>,
|
||||
Registers_x86_64>(((unw_addr_space_x86_64 *)as)->oas, arg);
|
||||
break;
|
||||
case CPU_TYPE_POWERPC:
|
||||
new ((void *)cursor)
|
||||
UnwindCursor<OtherAddressSpace<Pointer32<BigEndian> >, Registers_ppc>(
|
||||
((unw_addr_space_ppc *)as)->oas, arg);
|
||||
UnwindCursor<RemoteAddressSpace<Pointer32<BigEndian>>,
|
||||
Registers_ppc>(((unw_addr_space_ppc *)as)->oas, arg);
|
||||
break;
|
||||
default:
|
||||
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.
|
||||
_LIBUNWIND_EXPORT int unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
|
||||
unw_word_t value) {
|
||||
_LIBUNWIND_TRACE_API("unw_set_reg(cursor=%p, regNum=%d, value=0x%llX)",
|
||||
static_cast<void *>(cursor), regNum, (long long)value);
|
||||
_LIBUNWIND_TRACE_API("unw_set_reg(cursor=%p, regNum=%d, value=0x%" PRIxPTR ")",
|
||||
static_cast<void *>(cursor), regNum, value);
|
||||
typedef LocalAddressSpace::pint_t pint_t;
|
||||
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
|
||||
if (co->validReg(regNum)) {
|
||||
co->setReg(regNum, (pint_t)value);
|
||||
// specical case altering IP to re-find info (being called by personality
|
||||
// function)
|
||||
if (regNum == UNW_REG_IP)
|
||||
if (regNum == UNW_REG_IP) {
|
||||
unw_proc_info_t info;
|
||||
// First, get the FDE for the old location and then update it.
|
||||
co->getInfo(&info);
|
||||
co->setInfoBasedOnIPRegister(false);
|
||||
// If the original call expects stack adjustment, perform this now.
|
||||
// Normal frame unwinding would have included the offset already in the
|
||||
// CFA computation.
|
||||
// Note: for PA-RISC and other platforms where the stack grows up,
|
||||
// this should actually be - info.gp. LLVM doesn't currently support
|
||||
// any such platforms and Clang doesn't export a macro for them.
|
||||
if (info.gp)
|
||||
co->setReg(UNW_REG_SP, co->getReg(UNW_REG_SP) + info.gp);
|
||||
}
|
||||
return UNW_ESUCCESS;
|
||||
}
|
||||
return UNW_EBADREG;
|
||||
@ -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.
|
||||
_LIBUNWIND_EXPORT int unw_set_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum,
|
||||
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)",
|
||||
static_cast<void *>(cursor), regNum, value);
|
||||
#else
|
||||
@ -311,8 +329,8 @@ _LIBUNWIND_EXPORT void unw_save_vfp_as_X(unw_cursor_t *cursor) {
|
||||
#endif
|
||||
|
||||
|
||||
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
|
||||
/// SPI: walks cached dwarf entries
|
||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||
/// SPI: walks cached DWARF entries
|
||||
_LIBUNWIND_EXPORT void unw_iterate_dwarf_unwind_cache(void (*func)(
|
||||
unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) {
|
||||
_LIBUNWIND_TRACE_API("unw_iterate_dwarf_unwind_cache(func=%p)",
|
||||
@ -345,7 +363,8 @@ void _unw_remove_dynamic_fde(unw_word_t fde) {
|
||||
// fde is own mh_group
|
||||
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;
|
||||
}
|
||||
|
||||
_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
|
||||
|
||||
|
@ -33,7 +33,7 @@ extern void unw_iterate_dwarf_unwind_cache(void (*func)(unw_word_t ip_start,
|
||||
extern void _unw_add_dynamic_fde(unw_word_t fde);
|
||||
extern void _unw_remove_dynamic_fde(unw_word_t fde);
|
||||
|
||||
#if _LIBUNWIND_ARM_EHABI
|
||||
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||
extern const uint32_t* decode_eht_entry(const uint32_t*, size_t*, size_t*);
|
||||
extern _Unwind_Reason_Code _Unwind_VRS_Interpret(_Unwind_Context *context,
|
||||
const uint32_t *data,
|
||||
|
@ -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__
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user