| author | |
| committer | |
| log | bc8c4ec608ad541264994e62800679cdc5781760 |
| tree | 960a8c4cda24c08a2ae9e282031df0df49ffeb2a |
| parent | 4c386436ea5c5b3c98d91cb9b007e373faa8a257 |
| signature |
26 files changed, 16684 insertions(+), 0 deletions(-)
libunwind/include/__libunwind_config.h created+141| ... | ... | @@ -0,0 +1,141 @@ |
| 1 | //===------------------------- __libunwind_config.h -----------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is dual licensed under the MIT and the University of Illinois Open | |
| 6 | // Source Licenses. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | //===----------------------------------------------------------------------===// | |
| 9 | ||
| 10 | #ifndef ____LIBUNWIND_CONFIG_H__ | |
| 11 | #define ____LIBUNWIND_CONFIG_H__ | |
| 12 | ||
| 13 | #if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \ | |
| 14 | !defined(__ARM_DWARF_EH__) | |
| 15 | #define _LIBUNWIND_ARM_EHABI | |
| 16 | #endif | |
| 17 | ||
| 18 | #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86 8 | |
| 19 | #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64 32 | |
| 20 | #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC 112 | |
| 21 | #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64 116 | |
| 22 | #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64 95 | |
| 23 | #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM 287 | |
| 24 | #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K 32 | |
| 25 | #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS 65 | |
| 26 | #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC 31 | |
| 27 | ||
| 28 | #if defined(_LIBUNWIND_IS_NATIVE_ONLY) | |
| 29 | # if defined(__i386__) | |
| 30 | # define _LIBUNWIND_TARGET_I386 | |
| 31 | # define _LIBUNWIND_CONTEXT_SIZE 8 | |
| 32 | # define _LIBUNWIND_CURSOR_SIZE 15 | |
| 33 | # define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86 | |
| 34 | # elif defined(__x86_64__) | |
| 35 | # define _LIBUNWIND_TARGET_X86_64 1 | |
| 36 | # if defined(_WIN64) | |
| 37 | # define _LIBUNWIND_CONTEXT_SIZE 54 | |
| 38 | # ifdef __SEH__ | |
| 39 | # define _LIBUNWIND_CURSOR_SIZE 204 | |
| 40 | # else | |
| 41 | # define _LIBUNWIND_CURSOR_SIZE 66 | |
| 42 | # endif | |
| 43 | # else | |
| 44 | # define _LIBUNWIND_CONTEXT_SIZE 21 | |
| 45 | # define _LIBUNWIND_CURSOR_SIZE 33 | |
| 46 | # endif | |
| 47 | # define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64 | |
| 48 | # elif defined(__powerpc64__) | |
| 49 | # define _LIBUNWIND_TARGET_PPC64 1 | |
| 50 | # define _LIBUNWIND_CONTEXT_SIZE 167 | |
| 51 | # define _LIBUNWIND_CURSOR_SIZE 179 | |
| 52 | # define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64 | |
| 53 | # elif defined(__ppc__) | |
| 54 | # define _LIBUNWIND_TARGET_PPC 1 | |
| 55 | # define _LIBUNWIND_CONTEXT_SIZE 117 | |
| 56 | # define _LIBUNWIND_CURSOR_SIZE 124 | |
| 57 | # define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC | |
| 58 | # elif defined(__aarch64__) | |
| 59 | # define _LIBUNWIND_TARGET_AARCH64 1 | |
| 60 | # define _LIBUNWIND_CONTEXT_SIZE 66 | |
| 61 | # if defined(__SEH__) | |
| 62 | # define _LIBUNWIND_CURSOR_SIZE 164 | |
| 63 | # else | |
| 64 | # define _LIBUNWIND_CURSOR_SIZE 78 | |
| 65 | # endif | |
| 66 | # define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64 | |
| 67 | # elif defined(__arm__) | |
| 68 | # define _LIBUNWIND_TARGET_ARM 1 | |
| 69 | # if defined(__SEH__) | |
| 70 | # define _LIBUNWIND_CONTEXT_SIZE 42 | |
| 71 | # define _LIBUNWIND_CURSOR_SIZE 80 | |
| 72 | # elif defined(__ARM_WMMX) | |
| 73 | # define _LIBUNWIND_CONTEXT_SIZE 61 | |
| 74 | # define _LIBUNWIND_CURSOR_SIZE 68 | |
| 75 | # else | |
| 76 | # define _LIBUNWIND_CONTEXT_SIZE 42 | |
| 77 | # define _LIBUNWIND_CURSOR_SIZE 49 | |
| 78 | # endif | |
| 79 | # define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM | |
| 80 | # elif defined(__or1k__) | |
| 81 | # define _LIBUNWIND_TARGET_OR1K 1 | |
| 82 | # define _LIBUNWIND_CONTEXT_SIZE 16 | |
| 83 | # define _LIBUNWIND_CURSOR_SIZE 24 | |
| 84 | # define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K | |
| 85 | # elif defined(__mips__) | |
| 86 | # if defined(_ABIO32) && _MIPS_SIM == _ABIO32 | |
| 87 | # define _LIBUNWIND_TARGET_MIPS_O32 1 | |
| 88 | # if defined(__mips_hard_float) | |
| 89 | # define _LIBUNWIND_CONTEXT_SIZE 50 | |
| 90 | # define _LIBUNWIND_CURSOR_SIZE 57 | |
| 91 | # else | |
| 92 | # define _LIBUNWIND_CONTEXT_SIZE 18 | |
| 93 | # define _LIBUNWIND_CURSOR_SIZE 24 | |
| 94 | # endif | |
| 95 | # elif defined(_ABIN32) && _MIPS_SIM == _ABIN32 | |
| 96 | # define _LIBUNWIND_TARGET_MIPS_NEWABI 1 | |
| 97 | # if defined(__mips_hard_float) | |
| 98 | # define _LIBUNWIND_CONTEXT_SIZE 67 | |
| 99 | # define _LIBUNWIND_CURSOR_SIZE 74 | |
| 100 | # else | |
| 101 | # define _LIBUNWIND_CONTEXT_SIZE 35 | |
| 102 | # define _LIBUNWIND_CURSOR_SIZE 42 | |
| 103 | # endif | |
| 104 | # elif defined(_ABI64) && _MIPS_SIM == _ABI64 | |
| 105 | # define _LIBUNWIND_TARGET_MIPS_NEWABI 1 | |
| 106 | # if defined(__mips_hard_float) | |
| 107 | # define _LIBUNWIND_CONTEXT_SIZE 67 | |
| 108 | # define _LIBUNWIND_CURSOR_SIZE 79 | |
| 109 | # else | |
| 110 | # define _LIBUNWIND_CONTEXT_SIZE 35 | |
| 111 | # define _LIBUNWIND_CURSOR_SIZE 47 | |
| 112 | # endif | |
| 113 | # else | |
| 114 | # error "Unsupported MIPS ABI and/or environment" | |
| 115 | # endif | |
| 116 | # define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS | |
| 117 | # elif defined(__sparc__) | |
| 118 | #define _LIBUNWIND_TARGET_SPARC 1 | |
| 119 | #define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC | |
| 120 | #define _LIBUNWIND_CONTEXT_SIZE 16 | |
| 121 | #define _LIBUNWIND_CURSOR_SIZE 23 | |
| 122 | # else | |
| 123 | # error "Unsupported architecture." | |
| 124 | # endif | |
| 125 | #else // !_LIBUNWIND_IS_NATIVE_ONLY | |
| 126 | # define _LIBUNWIND_TARGET_I386 | |
| 127 | # define _LIBUNWIND_TARGET_X86_64 1 | |
| 128 | # define _LIBUNWIND_TARGET_PPC 1 | |
| 129 | # define _LIBUNWIND_TARGET_PPC64 1 | |
| 130 | # define _LIBUNWIND_TARGET_AARCH64 1 | |
| 131 | # define _LIBUNWIND_TARGET_ARM 1 | |
| 132 | # define _LIBUNWIND_TARGET_OR1K 1 | |
| 133 | # define _LIBUNWIND_TARGET_MIPS_O32 1 | |
| 134 | # define _LIBUNWIND_TARGET_MIPS_NEWABI 1 | |
| 135 | # define _LIBUNWIND_TARGET_SPARC 1 | |
| 136 | # define _LIBUNWIND_CONTEXT_SIZE 167 | |
| 137 | # define _LIBUNWIND_CURSOR_SIZE 179 | |
| 138 | # define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287 | |
| 139 | #endif // _LIBUNWIND_IS_NATIVE_ONLY | |
| 140 | ||
| 141 | #endif // ____LIBUNWIND_CONFIG_H__ |
libunwind/include/libunwind.h created+862| ... | ... | @@ -0,0 +1,862 @@ |
| 1 | //===---------------------------- libunwind.h -----------------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is dual licensed under the MIT and the University of Illinois Open | |
| 6 | // Source Licenses. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | // | |
| 9 | // Compatible with libunwind API documented at: | |
| 10 | // http://www.nongnu.org/libunwind/man/libunwind(3).html | |
| 11 | // | |
| 12 | //===----------------------------------------------------------------------===// | |
| 13 | ||
| 14 | #ifndef __LIBUNWIND__ | |
| 15 | #define __LIBUNWIND__ | |
| 16 | ||
| 17 | #include <__libunwind_config.h> | |
| 18 | ||
| 19 | #include <stdint.h> | |
| 20 | #include <stddef.h> | |
| 21 | ||
| 22 | #ifdef __APPLE__ | |
| 23 | #if __clang__ | |
| 24 | #if __has_include(<Availability.h>) | |
| 25 | #include <Availability.h> | |
| 26 | #endif | |
| 27 | #elif __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050 | |
| 28 | #include <Availability.h> | |
| 29 | #endif | |
| 30 | ||
| 31 | #ifdef __arm__ | |
| 32 | #define LIBUNWIND_AVAIL __attribute__((unavailable)) | |
| 33 | #elif defined(__OSX_AVAILABLE_STARTING) | |
| 34 | #define LIBUNWIND_AVAIL __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_5_0) | |
| 35 | #else | |
| 36 | #include <AvailabilityMacros.h> | |
| 37 | #ifdef AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER | |
| 38 | #define LIBUNWIND_AVAIL AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER | |
| 39 | #else | |
| 40 | #define LIBUNWIND_AVAIL __attribute__((unavailable)) | |
| 41 | #endif | |
| 42 | #endif | |
| 43 | #else | |
| 44 | #define LIBUNWIND_AVAIL | |
| 45 | #endif | |
| 46 | ||
| 47 | /* error codes */ | |
| 48 | enum { | |
| 49 | UNW_ESUCCESS = 0, /* no error */ | |
| 50 | UNW_EUNSPEC = -6540, /* unspecified (general) error */ | |
| 51 | UNW_ENOMEM = -6541, /* out of memory */ | |
| 52 | UNW_EBADREG = -6542, /* bad register number */ | |
| 53 | UNW_EREADONLYREG = -6543, /* attempt to write read-only register */ | |
| 54 | UNW_ESTOPUNWIND = -6544, /* stop unwinding */ | |
| 55 | UNW_EINVALIDIP = -6545, /* invalid IP */ | |
| 56 | UNW_EBADFRAME = -6546, /* bad frame */ | |
| 57 | UNW_EINVAL = -6547, /* unsupported operation or bad value */ | |
| 58 | UNW_EBADVERSION = -6548, /* unwind info has unsupported version */ | |
| 59 | UNW_ENOINFO = -6549 /* no unwind info found */ | |
| 60 | #if defined(_LIBUNWIND_TARGET_AARCH64) && !defined(_LIBUNWIND_IS_NATIVE_ONLY) | |
| 61 | , UNW_ECROSSRASIGNING = -6550 /* cross unwind with return address signing */ | |
| 62 | #endif | |
| 63 | }; | |
| 64 | ||
| 65 | struct unw_context_t { | |
| 66 | uint64_t data[_LIBUNWIND_CONTEXT_SIZE]; | |
| 67 | }; | |
| 68 | typedef struct unw_context_t unw_context_t; | |
| 69 | ||
| 70 | struct unw_cursor_t { | |
| 71 | uint64_t data[_LIBUNWIND_CURSOR_SIZE]; | |
| 72 | }; | |
| 73 | typedef struct unw_cursor_t unw_cursor_t; | |
| 74 | ||
| 75 | typedef struct unw_addr_space *unw_addr_space_t; | |
| 76 | ||
| 77 | typedef int unw_regnum_t; | |
| 78 | typedef uintptr_t unw_word_t; | |
| 79 | #if defined(__arm__) | |
| 80 | typedef uint64_t unw_fpreg_t; | |
| 81 | #else | |
| 82 | typedef double unw_fpreg_t; | |
| 83 | #endif | |
| 84 | ||
| 85 | struct unw_proc_info_t { | |
| 86 | unw_word_t start_ip; /* start address of function */ | |
| 87 | unw_word_t end_ip; /* address after end of function */ | |
| 88 | unw_word_t lsda; /* address of language specific data area, */ | |
| 89 | /* or zero if not used */ | |
| 90 | unw_word_t handler; /* personality routine, or zero if not used */ | |
| 91 | unw_word_t gp; /* not used */ | |
| 92 | unw_word_t flags; /* not used */ | |
| 93 | uint32_t format; /* compact unwind encoding, or zero if none */ | |
| 94 | uint32_t unwind_info_size; /* size of DWARF unwind info, or zero if none */ | |
| 95 | unw_word_t unwind_info; /* address of DWARF unwind info, or zero */ | |
| 96 | unw_word_t extra; /* mach_header of mach-o image containing func */ | |
| 97 | }; | |
| 98 | typedef struct unw_proc_info_t unw_proc_info_t; | |
| 99 | ||
| 100 | #ifdef __cplusplus | |
| 101 | extern "C" { | |
| 102 | #endif | |
| 103 | ||
| 104 | extern int unw_getcontext(unw_context_t *) LIBUNWIND_AVAIL; | |
| 105 | extern int unw_init_local(unw_cursor_t *, unw_context_t *) LIBUNWIND_AVAIL; | |
| 106 | extern int unw_step(unw_cursor_t *) LIBUNWIND_AVAIL; | |
| 107 | extern int unw_get_reg(unw_cursor_t *, unw_regnum_t, unw_word_t *) LIBUNWIND_AVAIL; | |
| 108 | extern int unw_get_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t *) LIBUNWIND_AVAIL; | |
| 109 | extern int unw_set_reg(unw_cursor_t *, unw_regnum_t, unw_word_t) LIBUNWIND_AVAIL; | |
| 110 | extern int unw_set_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t) LIBUNWIND_AVAIL; | |
| 111 | extern int unw_resume(unw_cursor_t *) LIBUNWIND_AVAIL; | |
| 112 | ||
| 113 | #ifdef __arm__ | |
| 114 | /* Save VFP registers in FSTMX format (instead of FSTMD). */ | |
| 115 | extern void unw_save_vfp_as_X(unw_cursor_t *) LIBUNWIND_AVAIL; | |
| 116 | #endif | |
| 117 | ||
| 118 | ||
| 119 | extern const char *unw_regname(unw_cursor_t *, unw_regnum_t) LIBUNWIND_AVAIL; | |
| 120 | extern int unw_get_proc_info(unw_cursor_t *, unw_proc_info_t *) LIBUNWIND_AVAIL; | |
| 121 | extern int unw_is_fpreg(unw_cursor_t *, unw_regnum_t) LIBUNWIND_AVAIL; | |
| 122 | extern int unw_is_signal_frame(unw_cursor_t *) LIBUNWIND_AVAIL; | |
| 123 | extern int unw_get_proc_name(unw_cursor_t *, char *, size_t, unw_word_t *) LIBUNWIND_AVAIL; | |
| 124 | //extern int unw_get_save_loc(unw_cursor_t*, int, unw_save_loc_t*); | |
| 125 | ||
| 126 | extern unw_addr_space_t unw_local_addr_space; | |
| 127 | ||
| 128 | #ifdef UNW_REMOTE | |
| 129 | /* | |
| 130 | * Mac OS X "remote" API for unwinding other processes on same machine | |
| 131 | * | |
| 132 | */ | |
| 133 | extern unw_addr_space_t unw_create_addr_space_for_task(task_t); | |
| 134 | extern void unw_destroy_addr_space(unw_addr_space_t); | |
| 135 | extern int unw_init_remote_thread(unw_cursor_t *, unw_addr_space_t, thread_t *); | |
| 136 | #endif /* UNW_REMOTE */ | |
| 137 | ||
| 138 | /* | |
| 139 | * traditional libunwind "remote" API | |
| 140 | * NOT IMPLEMENTED on Mac OS X | |
| 141 | * | |
| 142 | * extern int unw_init_remote(unw_cursor_t*, unw_addr_space_t, | |
| 143 | * thread_t*); | |
| 144 | * extern unw_accessors_t unw_get_accessors(unw_addr_space_t); | |
| 145 | * extern unw_addr_space_t unw_create_addr_space(unw_accessors_t, int); | |
| 146 | * extern void unw_flush_cache(unw_addr_space_t, unw_word_t, | |
| 147 | * unw_word_t); | |
| 148 | * extern int unw_set_caching_policy(unw_addr_space_t, | |
| 149 | * unw_caching_policy_t); | |
| 150 | * extern void _U_dyn_register(unw_dyn_info_t*); | |
| 151 | * extern void _U_dyn_cancel(unw_dyn_info_t*); | |
| 152 | */ | |
| 153 | ||
| 154 | #ifdef __cplusplus | |
| 155 | } | |
| 156 | #endif | |
| 157 | ||
| 158 | // architecture independent register numbers | |
| 159 | enum { | |
| 160 | UNW_REG_IP = -1, // instruction pointer | |
| 161 | UNW_REG_SP = -2, // stack pointer | |
| 162 | }; | |
| 163 | ||
| 164 | // 32-bit x86 registers | |
| 165 | enum { | |
| 166 | UNW_X86_EAX = 0, | |
| 167 | UNW_X86_ECX = 1, | |
| 168 | UNW_X86_EDX = 2, | |
| 169 | UNW_X86_EBX = 3, | |
| 170 | UNW_X86_EBP = 4, | |
| 171 | UNW_X86_ESP = 5, | |
| 172 | UNW_X86_ESI = 6, | |
| 173 | UNW_X86_EDI = 7 | |
| 174 | }; | |
| 175 | ||
| 176 | // 64-bit x86_64 registers | |
| 177 | enum { | |
| 178 | UNW_X86_64_RAX = 0, | |
| 179 | UNW_X86_64_RDX = 1, | |
| 180 | UNW_X86_64_RCX = 2, | |
| 181 | UNW_X86_64_RBX = 3, | |
| 182 | UNW_X86_64_RSI = 4, | |
| 183 | UNW_X86_64_RDI = 5, | |
| 184 | UNW_X86_64_RBP = 6, | |
| 185 | UNW_X86_64_RSP = 7, | |
| 186 | UNW_X86_64_R8 = 8, | |
| 187 | UNW_X86_64_R9 = 9, | |
| 188 | UNW_X86_64_R10 = 10, | |
| 189 | UNW_X86_64_R11 = 11, | |
| 190 | UNW_X86_64_R12 = 12, | |
| 191 | UNW_X86_64_R13 = 13, | |
| 192 | UNW_X86_64_R14 = 14, | |
| 193 | UNW_X86_64_R15 = 15, | |
| 194 | UNW_X86_64_RIP = 16, | |
| 195 | UNW_X86_64_XMM0 = 17, | |
| 196 | UNW_X86_64_XMM1 = 18, | |
| 197 | UNW_X86_64_XMM2 = 19, | |
| 198 | UNW_X86_64_XMM3 = 20, | |
| 199 | UNW_X86_64_XMM4 = 21, | |
| 200 | UNW_X86_64_XMM5 = 22, | |
| 201 | UNW_X86_64_XMM6 = 23, | |
| 202 | UNW_X86_64_XMM7 = 24, | |
| 203 | UNW_X86_64_XMM8 = 25, | |
| 204 | UNW_X86_64_XMM9 = 26, | |
| 205 | UNW_X86_64_XMM10 = 27, | |
| 206 | UNW_X86_64_XMM11 = 28, | |
| 207 | UNW_X86_64_XMM12 = 29, | |
| 208 | UNW_X86_64_XMM13 = 30, | |
| 209 | UNW_X86_64_XMM14 = 31, | |
| 210 | UNW_X86_64_XMM15 = 32, | |
| 211 | }; | |
| 212 | ||
| 213 | ||
| 214 | // 32-bit ppc register numbers | |
| 215 | enum { | |
| 216 | UNW_PPC_R0 = 0, | |
| 217 | UNW_PPC_R1 = 1, | |
| 218 | UNW_PPC_R2 = 2, | |
| 219 | UNW_PPC_R3 = 3, | |
| 220 | UNW_PPC_R4 = 4, | |
| 221 | UNW_PPC_R5 = 5, | |
| 222 | UNW_PPC_R6 = 6, | |
| 223 | UNW_PPC_R7 = 7, | |
| 224 | UNW_PPC_R8 = 8, | |
| 225 | UNW_PPC_R9 = 9, | |
| 226 | UNW_PPC_R10 = 10, | |
| 227 | UNW_PPC_R11 = 11, | |
| 228 | UNW_PPC_R12 = 12, | |
| 229 | UNW_PPC_R13 = 13, | |
| 230 | UNW_PPC_R14 = 14, | |
| 231 | UNW_PPC_R15 = 15, | |
| 232 | UNW_PPC_R16 = 16, | |
| 233 | UNW_PPC_R17 = 17, | |
| 234 | UNW_PPC_R18 = 18, | |
| 235 | UNW_PPC_R19 = 19, | |
| 236 | UNW_PPC_R20 = 20, | |
| 237 | UNW_PPC_R21 = 21, | |
| 238 | UNW_PPC_R22 = 22, | |
| 239 | UNW_PPC_R23 = 23, | |
| 240 | UNW_PPC_R24 = 24, | |
| 241 | UNW_PPC_R25 = 25, | |
| 242 | UNW_PPC_R26 = 26, | |
| 243 | UNW_PPC_R27 = 27, | |
| 244 | UNW_PPC_R28 = 28, | |
| 245 | UNW_PPC_R29 = 29, | |
| 246 | UNW_PPC_R30 = 30, | |
| 247 | UNW_PPC_R31 = 31, | |
| 248 | UNW_PPC_F0 = 32, | |
| 249 | UNW_PPC_F1 = 33, | |
| 250 | UNW_PPC_F2 = 34, | |
| 251 | UNW_PPC_F3 = 35, | |
| 252 | UNW_PPC_F4 = 36, | |
| 253 | UNW_PPC_F5 = 37, | |
| 254 | UNW_PPC_F6 = 38, | |
| 255 | UNW_PPC_F7 = 39, | |
| 256 | UNW_PPC_F8 = 40, | |
| 257 | UNW_PPC_F9 = 41, | |
| 258 | UNW_PPC_F10 = 42, | |
| 259 | UNW_PPC_F11 = 43, | |
| 260 | UNW_PPC_F12 = 44, | |
| 261 | UNW_PPC_F13 = 45, | |
| 262 | UNW_PPC_F14 = 46, | |
| 263 | UNW_PPC_F15 = 47, | |
| 264 | UNW_PPC_F16 = 48, | |
| 265 | UNW_PPC_F17 = 49, | |
| 266 | UNW_PPC_F18 = 50, | |
| 267 | UNW_PPC_F19 = 51, | |
| 268 | UNW_PPC_F20 = 52, | |
| 269 | UNW_PPC_F21 = 53, | |
| 270 | UNW_PPC_F22 = 54, | |
| 271 | UNW_PPC_F23 = 55, | |
| 272 | UNW_PPC_F24 = 56, | |
| 273 | UNW_PPC_F25 = 57, | |
| 274 | UNW_PPC_F26 = 58, | |
| 275 | UNW_PPC_F27 = 59, | |
| 276 | UNW_PPC_F28 = 60, | |
| 277 | UNW_PPC_F29 = 61, | |
| 278 | UNW_PPC_F30 = 62, | |
| 279 | UNW_PPC_F31 = 63, | |
| 280 | UNW_PPC_MQ = 64, | |
| 281 | UNW_PPC_LR = 65, | |
| 282 | UNW_PPC_CTR = 66, | |
| 283 | UNW_PPC_AP = 67, | |
| 284 | UNW_PPC_CR0 = 68, | |
| 285 | UNW_PPC_CR1 = 69, | |
| 286 | UNW_PPC_CR2 = 70, | |
| 287 | UNW_PPC_CR3 = 71, | |
| 288 | UNW_PPC_CR4 = 72, | |
| 289 | UNW_PPC_CR5 = 73, | |
| 290 | UNW_PPC_CR6 = 74, | |
| 291 | UNW_PPC_CR7 = 75, | |
| 292 | UNW_PPC_XER = 76, | |
| 293 | UNW_PPC_V0 = 77, | |
| 294 | UNW_PPC_V1 = 78, | |
| 295 | UNW_PPC_V2 = 79, | |
| 296 | UNW_PPC_V3 = 80, | |
| 297 | UNW_PPC_V4 = 81, | |
| 298 | UNW_PPC_V5 = 82, | |
| 299 | UNW_PPC_V6 = 83, | |
| 300 | UNW_PPC_V7 = 84, | |
| 301 | UNW_PPC_V8 = 85, | |
| 302 | UNW_PPC_V9 = 86, | |
| 303 | UNW_PPC_V10 = 87, | |
| 304 | UNW_PPC_V11 = 88, | |
| 305 | UNW_PPC_V12 = 89, | |
| 306 | UNW_PPC_V13 = 90, | |
| 307 | UNW_PPC_V14 = 91, | |
| 308 | UNW_PPC_V15 = 92, | |
| 309 | UNW_PPC_V16 = 93, | |
| 310 | UNW_PPC_V17 = 94, | |
| 311 | UNW_PPC_V18 = 95, | |
| 312 | UNW_PPC_V19 = 96, | |
| 313 | UNW_PPC_V20 = 97, | |
| 314 | UNW_PPC_V21 = 98, | |
| 315 | UNW_PPC_V22 = 99, | |
| 316 | UNW_PPC_V23 = 100, | |
| 317 | UNW_PPC_V24 = 101, | |
| 318 | UNW_PPC_V25 = 102, | |
| 319 | UNW_PPC_V26 = 103, | |
| 320 | UNW_PPC_V27 = 104, | |
| 321 | UNW_PPC_V28 = 105, | |
| 322 | UNW_PPC_V29 = 106, | |
| 323 | UNW_PPC_V30 = 107, | |
| 324 | UNW_PPC_V31 = 108, | |
| 325 | UNW_PPC_VRSAVE = 109, | |
| 326 | UNW_PPC_VSCR = 110, | |
| 327 | UNW_PPC_SPE_ACC = 111, | |
| 328 | UNW_PPC_SPEFSCR = 112 | |
| 329 | }; | |
| 330 | ||
| 331 | // 64-bit ppc register numbers | |
| 332 | enum { | |
| 333 | UNW_PPC64_R0 = 0, | |
| 334 | UNW_PPC64_R1 = 1, | |
| 335 | UNW_PPC64_R2 = 2, | |
| 336 | UNW_PPC64_R3 = 3, | |
| 337 | UNW_PPC64_R4 = 4, | |
| 338 | UNW_PPC64_R5 = 5, | |
| 339 | UNW_PPC64_R6 = 6, | |
| 340 | UNW_PPC64_R7 = 7, | |
| 341 | UNW_PPC64_R8 = 8, | |
| 342 | UNW_PPC64_R9 = 9, | |
| 343 | UNW_PPC64_R10 = 10, | |
| 344 | UNW_PPC64_R11 = 11, | |
| 345 | UNW_PPC64_R12 = 12, | |
| 346 | UNW_PPC64_R13 = 13, | |
| 347 | UNW_PPC64_R14 = 14, | |
| 348 | UNW_PPC64_R15 = 15, | |
| 349 | UNW_PPC64_R16 = 16, | |
| 350 | UNW_PPC64_R17 = 17, | |
| 351 | UNW_PPC64_R18 = 18, | |
| 352 | UNW_PPC64_R19 = 19, | |
| 353 | UNW_PPC64_R20 = 20, | |
| 354 | UNW_PPC64_R21 = 21, | |
| 355 | UNW_PPC64_R22 = 22, | |
| 356 | UNW_PPC64_R23 = 23, | |
| 357 | UNW_PPC64_R24 = 24, | |
| 358 | UNW_PPC64_R25 = 25, | |
| 359 | UNW_PPC64_R26 = 26, | |
| 360 | UNW_PPC64_R27 = 27, | |
| 361 | UNW_PPC64_R28 = 28, | |
| 362 | UNW_PPC64_R29 = 29, | |
| 363 | UNW_PPC64_R30 = 30, | |
| 364 | UNW_PPC64_R31 = 31, | |
| 365 | UNW_PPC64_F0 = 32, | |
| 366 | UNW_PPC64_F1 = 33, | |
| 367 | UNW_PPC64_F2 = 34, | |
| 368 | UNW_PPC64_F3 = 35, | |
| 369 | UNW_PPC64_F4 = 36, | |
| 370 | UNW_PPC64_F5 = 37, | |
| 371 | UNW_PPC64_F6 = 38, | |
| 372 | UNW_PPC64_F7 = 39, | |
| 373 | UNW_PPC64_F8 = 40, | |
| 374 | UNW_PPC64_F9 = 41, | |
| 375 | UNW_PPC64_F10 = 42, | |
| 376 | UNW_PPC64_F11 = 43, | |
| 377 | UNW_PPC64_F12 = 44, | |
| 378 | UNW_PPC64_F13 = 45, | |
| 379 | UNW_PPC64_F14 = 46, | |
| 380 | UNW_PPC64_F15 = 47, | |
| 381 | UNW_PPC64_F16 = 48, | |
| 382 | UNW_PPC64_F17 = 49, | |
| 383 | UNW_PPC64_F18 = 50, | |
| 384 | UNW_PPC64_F19 = 51, | |
| 385 | UNW_PPC64_F20 = 52, | |
| 386 | UNW_PPC64_F21 = 53, | |
| 387 | UNW_PPC64_F22 = 54, | |
| 388 | UNW_PPC64_F23 = 55, | |
| 389 | UNW_PPC64_F24 = 56, | |
| 390 | UNW_PPC64_F25 = 57, | |
| 391 | UNW_PPC64_F26 = 58, | |
| 392 | UNW_PPC64_F27 = 59, | |
| 393 | UNW_PPC64_F28 = 60, | |
| 394 | UNW_PPC64_F29 = 61, | |
| 395 | UNW_PPC64_F30 = 62, | |
| 396 | UNW_PPC64_F31 = 63, | |
| 397 | // 64: reserved | |
| 398 | UNW_PPC64_LR = 65, | |
| 399 | UNW_PPC64_CTR = 66, | |
| 400 | // 67: reserved | |
| 401 | UNW_PPC64_CR0 = 68, | |
| 402 | UNW_PPC64_CR1 = 69, | |
| 403 | UNW_PPC64_CR2 = 70, | |
| 404 | UNW_PPC64_CR3 = 71, | |
| 405 | UNW_PPC64_CR4 = 72, | |
| 406 | UNW_PPC64_CR5 = 73, | |
| 407 | UNW_PPC64_CR6 = 74, | |
| 408 | UNW_PPC64_CR7 = 75, | |
| 409 | UNW_PPC64_XER = 76, | |
| 410 | UNW_PPC64_V0 = 77, | |
| 411 | UNW_PPC64_V1 = 78, | |
| 412 | UNW_PPC64_V2 = 79, | |
| 413 | UNW_PPC64_V3 = 80, | |
| 414 | UNW_PPC64_V4 = 81, | |
| 415 | UNW_PPC64_V5 = 82, | |
| 416 | UNW_PPC64_V6 = 83, | |
| 417 | UNW_PPC64_V7 = 84, | |
| 418 | UNW_PPC64_V8 = 85, | |
| 419 | UNW_PPC64_V9 = 86, | |
| 420 | UNW_PPC64_V10 = 87, | |
| 421 | UNW_PPC64_V11 = 88, | |
| 422 | UNW_PPC64_V12 = 89, | |
| 423 | UNW_PPC64_V13 = 90, | |
| 424 | UNW_PPC64_V14 = 91, | |
| 425 | UNW_PPC64_V15 = 92, | |
| 426 | UNW_PPC64_V16 = 93, | |
| 427 | UNW_PPC64_V17 = 94, | |
| 428 | UNW_PPC64_V18 = 95, | |
| 429 | UNW_PPC64_V19 = 96, | |
| 430 | UNW_PPC64_V20 = 97, | |
| 431 | UNW_PPC64_V21 = 98, | |
| 432 | UNW_PPC64_V22 = 99, | |
| 433 | UNW_PPC64_V23 = 100, | |
| 434 | UNW_PPC64_V24 = 101, | |
| 435 | UNW_PPC64_V25 = 102, | |
| 436 | UNW_PPC64_V26 = 103, | |
| 437 | UNW_PPC64_V27 = 104, | |
| 438 | UNW_PPC64_V28 = 105, | |
| 439 | UNW_PPC64_V29 = 106, | |
| 440 | UNW_PPC64_V30 = 107, | |
| 441 | UNW_PPC64_V31 = 108, | |
| 442 | // 109, 111-113: OpenPOWER ELF V2 ABI: reserved | |
| 443 | // Borrowing VRSAVE number from PPC32. | |
| 444 | UNW_PPC64_VRSAVE = 109, | |
| 445 | UNW_PPC64_VSCR = 110, | |
| 446 | UNW_PPC64_TFHAR = 114, | |
| 447 | UNW_PPC64_TFIAR = 115, | |
| 448 | UNW_PPC64_TEXASR = 116, | |
| 449 | UNW_PPC64_VS0 = UNW_PPC64_F0, | |
| 450 | UNW_PPC64_VS1 = UNW_PPC64_F1, | |
| 451 | UNW_PPC64_VS2 = UNW_PPC64_F2, | |
| 452 | UNW_PPC64_VS3 = UNW_PPC64_F3, | |
| 453 | UNW_PPC64_VS4 = UNW_PPC64_F4, | |
| 454 | UNW_PPC64_VS5 = UNW_PPC64_F5, | |
| 455 | UNW_PPC64_VS6 = UNW_PPC64_F6, | |
| 456 | UNW_PPC64_VS7 = UNW_PPC64_F7, | |
| 457 | UNW_PPC64_VS8 = UNW_PPC64_F8, | |
| 458 | UNW_PPC64_VS9 = UNW_PPC64_F9, | |
| 459 | UNW_PPC64_VS10 = UNW_PPC64_F10, | |
| 460 | UNW_PPC64_VS11 = UNW_PPC64_F11, | |
| 461 | UNW_PPC64_VS12 = UNW_PPC64_F12, | |
| 462 | UNW_PPC64_VS13 = UNW_PPC64_F13, | |
| 463 | UNW_PPC64_VS14 = UNW_PPC64_F14, | |
| 464 | UNW_PPC64_VS15 = UNW_PPC64_F15, | |
| 465 | UNW_PPC64_VS16 = UNW_PPC64_F16, | |
| 466 | UNW_PPC64_VS17 = UNW_PPC64_F17, | |
| 467 | UNW_PPC64_VS18 = UNW_PPC64_F18, | |
| 468 | UNW_PPC64_VS19 = UNW_PPC64_F19, | |
| 469 | UNW_PPC64_VS20 = UNW_PPC64_F20, | |
| 470 | UNW_PPC64_VS21 = UNW_PPC64_F21, | |
| 471 | UNW_PPC64_VS22 = UNW_PPC64_F22, | |
| 472 | UNW_PPC64_VS23 = UNW_PPC64_F23, | |
| 473 | UNW_PPC64_VS24 = UNW_PPC64_F24, | |
| 474 | UNW_PPC64_VS25 = UNW_PPC64_F25, | |
| 475 | UNW_PPC64_VS26 = UNW_PPC64_F26, | |
| 476 | UNW_PPC64_VS27 = UNW_PPC64_F27, | |
| 477 | UNW_PPC64_VS28 = UNW_PPC64_F28, | |
| 478 | UNW_PPC64_VS29 = UNW_PPC64_F29, | |
| 479 | UNW_PPC64_VS30 = UNW_PPC64_F30, | |
| 480 | UNW_PPC64_VS31 = UNW_PPC64_F31, | |
| 481 | UNW_PPC64_VS32 = UNW_PPC64_V0, | |
| 482 | UNW_PPC64_VS33 = UNW_PPC64_V1, | |
| 483 | UNW_PPC64_VS34 = UNW_PPC64_V2, | |
| 484 | UNW_PPC64_VS35 = UNW_PPC64_V3, | |
| 485 | UNW_PPC64_VS36 = UNW_PPC64_V4, | |
| 486 | UNW_PPC64_VS37 = UNW_PPC64_V5, | |
| 487 | UNW_PPC64_VS38 = UNW_PPC64_V6, | |
| 488 | UNW_PPC64_VS39 = UNW_PPC64_V7, | |
| 489 | UNW_PPC64_VS40 = UNW_PPC64_V8, | |
| 490 | UNW_PPC64_VS41 = UNW_PPC64_V9, | |
| 491 | UNW_PPC64_VS42 = UNW_PPC64_V10, | |
| 492 | UNW_PPC64_VS43 = UNW_PPC64_V11, | |
| 493 | UNW_PPC64_VS44 = UNW_PPC64_V12, | |
| 494 | UNW_PPC64_VS45 = UNW_PPC64_V13, | |
| 495 | UNW_PPC64_VS46 = UNW_PPC64_V14, | |
| 496 | UNW_PPC64_VS47 = UNW_PPC64_V15, | |
| 497 | UNW_PPC64_VS48 = UNW_PPC64_V16, | |
| 498 | UNW_PPC64_VS49 = UNW_PPC64_V17, | |
| 499 | UNW_PPC64_VS50 = UNW_PPC64_V18, | |
| 500 | UNW_PPC64_VS51 = UNW_PPC64_V19, | |
| 501 | UNW_PPC64_VS52 = UNW_PPC64_V20, | |
| 502 | UNW_PPC64_VS53 = UNW_PPC64_V21, | |
| 503 | UNW_PPC64_VS54 = UNW_PPC64_V22, | |
| 504 | UNW_PPC64_VS55 = UNW_PPC64_V23, | |
| 505 | UNW_PPC64_VS56 = UNW_PPC64_V24, | |
| 506 | UNW_PPC64_VS57 = UNW_PPC64_V25, | |
| 507 | UNW_PPC64_VS58 = UNW_PPC64_V26, | |
| 508 | UNW_PPC64_VS59 = UNW_PPC64_V27, | |
| 509 | UNW_PPC64_VS60 = UNW_PPC64_V28, | |
| 510 | UNW_PPC64_VS61 = UNW_PPC64_V29, | |
| 511 | UNW_PPC64_VS62 = UNW_PPC64_V30, | |
| 512 | UNW_PPC64_VS63 = UNW_PPC64_V31 | |
| 513 | }; | |
| 514 | ||
| 515 | // 64-bit ARM64 registers | |
| 516 | enum { | |
| 517 | UNW_ARM64_X0 = 0, | |
| 518 | UNW_ARM64_X1 = 1, | |
| 519 | UNW_ARM64_X2 = 2, | |
| 520 | UNW_ARM64_X3 = 3, | |
| 521 | UNW_ARM64_X4 = 4, | |
| 522 | UNW_ARM64_X5 = 5, | |
| 523 | UNW_ARM64_X6 = 6, | |
| 524 | UNW_ARM64_X7 = 7, | |
| 525 | UNW_ARM64_X8 = 8, | |
| 526 | UNW_ARM64_X9 = 9, | |
| 527 | UNW_ARM64_X10 = 10, | |
| 528 | UNW_ARM64_X11 = 11, | |
| 529 | UNW_ARM64_X12 = 12, | |
| 530 | UNW_ARM64_X13 = 13, | |
| 531 | UNW_ARM64_X14 = 14, | |
| 532 | UNW_ARM64_X15 = 15, | |
| 533 | UNW_ARM64_X16 = 16, | |
| 534 | UNW_ARM64_X17 = 17, | |
| 535 | UNW_ARM64_X18 = 18, | |
| 536 | UNW_ARM64_X19 = 19, | |
| 537 | UNW_ARM64_X20 = 20, | |
| 538 | UNW_ARM64_X21 = 21, | |
| 539 | UNW_ARM64_X22 = 22, | |
| 540 | UNW_ARM64_X23 = 23, | |
| 541 | UNW_ARM64_X24 = 24, | |
| 542 | UNW_ARM64_X25 = 25, | |
| 543 | UNW_ARM64_X26 = 26, | |
| 544 | UNW_ARM64_X27 = 27, | |
| 545 | UNW_ARM64_X28 = 28, | |
| 546 | UNW_ARM64_X29 = 29, | |
| 547 | UNW_ARM64_FP = 29, | |
| 548 | UNW_ARM64_X30 = 30, | |
| 549 | UNW_ARM64_LR = 30, | |
| 550 | UNW_ARM64_X31 = 31, | |
| 551 | UNW_ARM64_SP = 31, | |
| 552 | // reserved block | |
| 553 | UNW_ARM64_RA_SIGN_STATE = 34, | |
| 554 | // reserved block | |
| 555 | UNW_ARM64_D0 = 64, | |
| 556 | UNW_ARM64_D1 = 65, | |
| 557 | UNW_ARM64_D2 = 66, | |
| 558 | UNW_ARM64_D3 = 67, | |
| 559 | UNW_ARM64_D4 = 68, | |
| 560 | UNW_ARM64_D5 = 69, | |
| 561 | UNW_ARM64_D6 = 70, | |
| 562 | UNW_ARM64_D7 = 71, | |
| 563 | UNW_ARM64_D8 = 72, | |
| 564 | UNW_ARM64_D9 = 73, | |
| 565 | UNW_ARM64_D10 = 74, | |
| 566 | UNW_ARM64_D11 = 75, | |
| 567 | UNW_ARM64_D12 = 76, | |
| 568 | UNW_ARM64_D13 = 77, | |
| 569 | UNW_ARM64_D14 = 78, | |
| 570 | UNW_ARM64_D15 = 79, | |
| 571 | UNW_ARM64_D16 = 80, | |
| 572 | UNW_ARM64_D17 = 81, | |
| 573 | UNW_ARM64_D18 = 82, | |
| 574 | UNW_ARM64_D19 = 83, | |
| 575 | UNW_ARM64_D20 = 84, | |
| 576 | UNW_ARM64_D21 = 85, | |
| 577 | UNW_ARM64_D22 = 86, | |
| 578 | UNW_ARM64_D23 = 87, | |
| 579 | UNW_ARM64_D24 = 88, | |
| 580 | UNW_ARM64_D25 = 89, | |
| 581 | UNW_ARM64_D26 = 90, | |
| 582 | UNW_ARM64_D27 = 91, | |
| 583 | UNW_ARM64_D28 = 92, | |
| 584 | UNW_ARM64_D29 = 93, | |
| 585 | UNW_ARM64_D30 = 94, | |
| 586 | UNW_ARM64_D31 = 95, | |
| 587 | }; | |
| 588 | ||
| 589 | // 32-bit ARM registers. Numbers match DWARF for ARM spec #3.1 Table 1. | |
| 590 | // Naming scheme uses recommendations given in Note 4 for VFP-v2 and VFP-v3. | |
| 591 | // In this scheme, even though the 64-bit floating point registers D0-D31 | |
| 592 | // overlap physically with the 32-bit floating pointer registers S0-S31, | |
| 593 | // they are given a non-overlapping range of register numbers. | |
| 594 | // | |
| 595 | // Commented out ranges are not preserved during unwinding. | |
| 596 | enum { | |
| 597 | UNW_ARM_R0 = 0, | |
| 598 | UNW_ARM_R1 = 1, | |
| 599 | UNW_ARM_R2 = 2, | |
| 600 | UNW_ARM_R3 = 3, | |
| 601 | UNW_ARM_R4 = 4, | |
| 602 | UNW_ARM_R5 = 5, | |
| 603 | UNW_ARM_R6 = 6, | |
| 604 | UNW_ARM_R7 = 7, | |
| 605 | UNW_ARM_R8 = 8, | |
| 606 | UNW_ARM_R9 = 9, | |
| 607 | UNW_ARM_R10 = 10, | |
| 608 | UNW_ARM_R11 = 11, | |
| 609 | UNW_ARM_R12 = 12, | |
| 610 | UNW_ARM_SP = 13, // Logical alias for UNW_REG_SP | |
| 611 | UNW_ARM_R13 = 13, | |
| 612 | UNW_ARM_LR = 14, | |
| 613 | UNW_ARM_R14 = 14, | |
| 614 | UNW_ARM_IP = 15, // Logical alias for UNW_REG_IP | |
| 615 | UNW_ARM_R15 = 15, | |
| 616 | // 16-63 -- OBSOLETE. Used in VFP1 to represent both S0-S31 and D0-D31. | |
| 617 | UNW_ARM_S0 = 64, | |
| 618 | UNW_ARM_S1 = 65, | |
| 619 | UNW_ARM_S2 = 66, | |
| 620 | UNW_ARM_S3 = 67, | |
| 621 | UNW_ARM_S4 = 68, | |
| 622 | UNW_ARM_S5 = 69, | |
| 623 | UNW_ARM_S6 = 70, | |
| 624 | UNW_ARM_S7 = 71, | |
| 625 | UNW_ARM_S8 = 72, | |
| 626 | UNW_ARM_S9 = 73, | |
| 627 | UNW_ARM_S10 = 74, | |
| 628 | UNW_ARM_S11 = 75, | |
| 629 | UNW_ARM_S12 = 76, | |
| 630 | UNW_ARM_S13 = 77, | |
| 631 | UNW_ARM_S14 = 78, | |
| 632 | UNW_ARM_S15 = 79, | |
| 633 | UNW_ARM_S16 = 80, | |
| 634 | UNW_ARM_S17 = 81, | |
| 635 | UNW_ARM_S18 = 82, | |
| 636 | UNW_ARM_S19 = 83, | |
| 637 | UNW_ARM_S20 = 84, | |
| 638 | UNW_ARM_S21 = 85, | |
| 639 | UNW_ARM_S22 = 86, | |
| 640 | UNW_ARM_S23 = 87, | |
| 641 | UNW_ARM_S24 = 88, | |
| 642 | UNW_ARM_S25 = 89, | |
| 643 | UNW_ARM_S26 = 90, | |
| 644 | UNW_ARM_S27 = 91, | |
| 645 | UNW_ARM_S28 = 92, | |
| 646 | UNW_ARM_S29 = 93, | |
| 647 | UNW_ARM_S30 = 94, | |
| 648 | UNW_ARM_S31 = 95, | |
| 649 | // 96-103 -- OBSOLETE. F0-F7. Used by the FPA system. Superseded by VFP. | |
| 650 | // 104-111 -- wCGR0-wCGR7, ACC0-ACC7 (Intel wireless MMX) | |
| 651 | UNW_ARM_WR0 = 112, | |
| 652 | UNW_ARM_WR1 = 113, | |
| 653 | UNW_ARM_WR2 = 114, | |
| 654 | UNW_ARM_WR3 = 115, | |
| 655 | UNW_ARM_WR4 = 116, | |
| 656 | UNW_ARM_WR5 = 117, | |
| 657 | UNW_ARM_WR6 = 118, | |
| 658 | UNW_ARM_WR7 = 119, | |
| 659 | UNW_ARM_WR8 = 120, | |
| 660 | UNW_ARM_WR9 = 121, | |
| 661 | UNW_ARM_WR10 = 122, | |
| 662 | UNW_ARM_WR11 = 123, | |
| 663 | UNW_ARM_WR12 = 124, | |
| 664 | UNW_ARM_WR13 = 125, | |
| 665 | UNW_ARM_WR14 = 126, | |
| 666 | UNW_ARM_WR15 = 127, | |
| 667 | // 128-133 -- SPSR, SPSR_{FIQ|IRQ|ABT|UND|SVC} | |
| 668 | // 134-143 -- Reserved | |
| 669 | // 144-150 -- R8_USR-R14_USR | |
| 670 | // 151-157 -- R8_FIQ-R14_FIQ | |
| 671 | // 158-159 -- R13_IRQ-R14_IRQ | |
| 672 | // 160-161 -- R13_ABT-R14_ABT | |
| 673 | // 162-163 -- R13_UND-R14_UND | |
| 674 | // 164-165 -- R13_SVC-R14_SVC | |
| 675 | // 166-191 -- Reserved | |
| 676 | UNW_ARM_WC0 = 192, | |
| 677 | UNW_ARM_WC1 = 193, | |
| 678 | UNW_ARM_WC2 = 194, | |
| 679 | UNW_ARM_WC3 = 195, | |
| 680 | // 196-199 -- wC4-wC7 (Intel wireless MMX control) | |
| 681 | // 200-255 -- Reserved | |
| 682 | UNW_ARM_D0 = 256, | |
| 683 | UNW_ARM_D1 = 257, | |
| 684 | UNW_ARM_D2 = 258, | |
| 685 | UNW_ARM_D3 = 259, | |
| 686 | UNW_ARM_D4 = 260, | |
| 687 | UNW_ARM_D5 = 261, | |
| 688 | UNW_ARM_D6 = 262, | |
| 689 | UNW_ARM_D7 = 263, | |
| 690 | UNW_ARM_D8 = 264, | |
| 691 | UNW_ARM_D9 = 265, | |
| 692 | UNW_ARM_D10 = 266, | |
| 693 | UNW_ARM_D11 = 267, | |
| 694 | UNW_ARM_D12 = 268, | |
| 695 | UNW_ARM_D13 = 269, | |
| 696 | UNW_ARM_D14 = 270, | |
| 697 | UNW_ARM_D15 = 271, | |
| 698 | UNW_ARM_D16 = 272, | |
| 699 | UNW_ARM_D17 = 273, | |
| 700 | UNW_ARM_D18 = 274, | |
| 701 | UNW_ARM_D19 = 275, | |
| 702 | UNW_ARM_D20 = 276, | |
| 703 | UNW_ARM_D21 = 277, | |
| 704 | UNW_ARM_D22 = 278, | |
| 705 | UNW_ARM_D23 = 279, | |
| 706 | UNW_ARM_D24 = 280, | |
| 707 | UNW_ARM_D25 = 281, | |
| 708 | UNW_ARM_D26 = 282, | |
| 709 | UNW_ARM_D27 = 283, | |
| 710 | UNW_ARM_D28 = 284, | |
| 711 | UNW_ARM_D29 = 285, | |
| 712 | UNW_ARM_D30 = 286, | |
| 713 | UNW_ARM_D31 = 287, | |
| 714 | // 288-319 -- Reserved for VFP/Neon | |
| 715 | // 320-8191 -- Reserved | |
| 716 | // 8192-16383 -- Unspecified vendor co-processor register. | |
| 717 | }; | |
| 718 | ||
| 719 | // OpenRISC1000 register numbers | |
| 720 | enum { | |
| 721 | UNW_OR1K_R0 = 0, | |
| 722 | UNW_OR1K_R1 = 1, | |
| 723 | UNW_OR1K_R2 = 2, | |
| 724 | UNW_OR1K_R3 = 3, | |
| 725 | UNW_OR1K_R4 = 4, | |
| 726 | UNW_OR1K_R5 = 5, | |
| 727 | UNW_OR1K_R6 = 6, | |
| 728 | UNW_OR1K_R7 = 7, | |
| 729 | UNW_OR1K_R8 = 8, | |
| 730 | UNW_OR1K_R9 = 9, | |
| 731 | UNW_OR1K_R10 = 10, | |
| 732 | UNW_OR1K_R11 = 11, | |
| 733 | UNW_OR1K_R12 = 12, | |
| 734 | UNW_OR1K_R13 = 13, | |
| 735 | UNW_OR1K_R14 = 14, | |
| 736 | UNW_OR1K_R15 = 15, | |
| 737 | UNW_OR1K_R16 = 16, | |
| 738 | UNW_OR1K_R17 = 17, | |
| 739 | UNW_OR1K_R18 = 18, | |
| 740 | UNW_OR1K_R19 = 19, | |
| 741 | UNW_OR1K_R20 = 20, | |
| 742 | UNW_OR1K_R21 = 21, | |
| 743 | UNW_OR1K_R22 = 22, | |
| 744 | UNW_OR1K_R23 = 23, | |
| 745 | UNW_OR1K_R24 = 24, | |
| 746 | UNW_OR1K_R25 = 25, | |
| 747 | UNW_OR1K_R26 = 26, | |
| 748 | UNW_OR1K_R27 = 27, | |
| 749 | UNW_OR1K_R28 = 28, | |
| 750 | UNW_OR1K_R29 = 29, | |
| 751 | UNW_OR1K_R30 = 30, | |
| 752 | UNW_OR1K_R31 = 31, | |
| 753 | UNW_OR1K_EPCR = 32, | |
| 754 | }; | |
| 755 | ||
| 756 | // MIPS registers | |
| 757 | enum { | |
| 758 | UNW_MIPS_R0 = 0, | |
| 759 | UNW_MIPS_R1 = 1, | |
| 760 | UNW_MIPS_R2 = 2, | |
| 761 | UNW_MIPS_R3 = 3, | |
| 762 | UNW_MIPS_R4 = 4, | |
| 763 | UNW_MIPS_R5 = 5, | |
| 764 | UNW_MIPS_R6 = 6, | |
| 765 | UNW_MIPS_R7 = 7, | |
| 766 | UNW_MIPS_R8 = 8, | |
| 767 | UNW_MIPS_R9 = 9, | |
| 768 | UNW_MIPS_R10 = 10, | |
| 769 | UNW_MIPS_R11 = 11, | |
| 770 | UNW_MIPS_R12 = 12, | |
| 771 | UNW_MIPS_R13 = 13, | |
| 772 | UNW_MIPS_R14 = 14, | |
| 773 | UNW_MIPS_R15 = 15, | |
| 774 | UNW_MIPS_R16 = 16, | |
| 775 | UNW_MIPS_R17 = 17, | |
| 776 | UNW_MIPS_R18 = 18, | |
| 777 | UNW_MIPS_R19 = 19, | |
| 778 | UNW_MIPS_R20 = 20, | |
| 779 | UNW_MIPS_R21 = 21, | |
| 780 | UNW_MIPS_R22 = 22, | |
| 781 | UNW_MIPS_R23 = 23, | |
| 782 | UNW_MIPS_R24 = 24, | |
| 783 | UNW_MIPS_R25 = 25, | |
| 784 | UNW_MIPS_R26 = 26, | |
| 785 | UNW_MIPS_R27 = 27, | |
| 786 | UNW_MIPS_R28 = 28, | |
| 787 | UNW_MIPS_R29 = 29, | |
| 788 | UNW_MIPS_R30 = 30, | |
| 789 | UNW_MIPS_R31 = 31, | |
| 790 | UNW_MIPS_F0 = 32, | |
| 791 | UNW_MIPS_F1 = 33, | |
| 792 | UNW_MIPS_F2 = 34, | |
| 793 | UNW_MIPS_F3 = 35, | |
| 794 | UNW_MIPS_F4 = 36, | |
| 795 | UNW_MIPS_F5 = 37, | |
| 796 | UNW_MIPS_F6 = 38, | |
| 797 | UNW_MIPS_F7 = 39, | |
| 798 | UNW_MIPS_F8 = 40, | |
| 799 | UNW_MIPS_F9 = 41, | |
| 800 | UNW_MIPS_F10 = 42, | |
| 801 | UNW_MIPS_F11 = 43, | |
| 802 | UNW_MIPS_F12 = 44, | |
| 803 | UNW_MIPS_F13 = 45, | |
| 804 | UNW_MIPS_F14 = 46, | |
| 805 | UNW_MIPS_F15 = 47, | |
| 806 | UNW_MIPS_F16 = 48, | |
| 807 | UNW_MIPS_F17 = 49, | |
| 808 | UNW_MIPS_F18 = 50, | |
| 809 | UNW_MIPS_F19 = 51, | |
| 810 | UNW_MIPS_F20 = 52, | |
| 811 | UNW_MIPS_F21 = 53, | |
| 812 | UNW_MIPS_F22 = 54, | |
| 813 | UNW_MIPS_F23 = 55, | |
| 814 | UNW_MIPS_F24 = 56, | |
| 815 | UNW_MIPS_F25 = 57, | |
| 816 | UNW_MIPS_F26 = 58, | |
| 817 | UNW_MIPS_F27 = 59, | |
| 818 | UNW_MIPS_F28 = 60, | |
| 819 | UNW_MIPS_F29 = 61, | |
| 820 | UNW_MIPS_F30 = 62, | |
| 821 | UNW_MIPS_F31 = 63, | |
| 822 | UNW_MIPS_HI = 64, | |
| 823 | UNW_MIPS_LO = 65, | |
| 824 | }; | |
| 825 | ||
| 826 | // SPARC registers | |
| 827 | enum { | |
| 828 | UNW_SPARC_G0 = 0, | |
| 829 | UNW_SPARC_G1 = 1, | |
| 830 | UNW_SPARC_G2 = 2, | |
| 831 | UNW_SPARC_G3 = 3, | |
| 832 | UNW_SPARC_G4 = 4, | |
| 833 | UNW_SPARC_G5 = 5, | |
| 834 | UNW_SPARC_G6 = 6, | |
| 835 | UNW_SPARC_G7 = 7, | |
| 836 | UNW_SPARC_O0 = 8, | |
| 837 | UNW_SPARC_O1 = 9, | |
| 838 | UNW_SPARC_O2 = 10, | |
| 839 | UNW_SPARC_O3 = 11, | |
| 840 | UNW_SPARC_O4 = 12, | |
| 841 | UNW_SPARC_O5 = 13, | |
| 842 | UNW_SPARC_O6 = 14, | |
| 843 | UNW_SPARC_O7 = 15, | |
| 844 | UNW_SPARC_L0 = 16, | |
| 845 | UNW_SPARC_L1 = 17, | |
| 846 | UNW_SPARC_L2 = 18, | |
| 847 | UNW_SPARC_L3 = 19, | |
| 848 | UNW_SPARC_L4 = 20, | |
| 849 | UNW_SPARC_L5 = 21, | |
| 850 | UNW_SPARC_L6 = 22, | |
| 851 | UNW_SPARC_L7 = 23, | |
| 852 | UNW_SPARC_I0 = 24, | |
| 853 | UNW_SPARC_I1 = 25, | |
| 854 | UNW_SPARC_I2 = 26, | |
| 855 | UNW_SPARC_I3 = 27, | |
| 856 | UNW_SPARC_I4 = 28, | |
| 857 | UNW_SPARC_I5 = 29, | |
| 858 | UNW_SPARC_I6 = 30, | |
| 859 | UNW_SPARC_I7 = 31, | |
| 860 | }; | |
| 861 | ||
| 862 | #endif |
libunwind/include/mach-o/compact_unwind_encoding.h created+478| ... | ... | @@ -0,0 +1,478 @@ |
| 1 | //===------------------ mach-o/compact_unwind_encoding.h ------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is dual licensed under the MIT and the University of Illinois Open | |
| 6 | // Source Licenses. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | // | |
| 9 | // Darwin's alternative to DWARF based unwind encodings. | |
| 10 | // | |
| 11 | //===----------------------------------------------------------------------===// | |
| 12 | ||
| 13 | ||
| 14 | #ifndef __COMPACT_UNWIND_ENCODING__ | |
| 15 | #define __COMPACT_UNWIND_ENCODING__ | |
| 16 | ||
| 17 | #include <stdint.h> | |
| 18 | ||
| 19 | // | |
| 20 | // Compilers can emit standard DWARF FDEs in the __TEXT,__eh_frame section | |
| 21 | // of object files. Or compilers can emit compact unwind information in | |
| 22 | // the __LD,__compact_unwind section. | |
| 23 | // | |
| 24 | // When the linker creates a final linked image, it will create a | |
| 25 | // __TEXT,__unwind_info section. This section is a small and fast way for the | |
| 26 | // runtime to access unwind info for any given function. If the compiler | |
| 27 | // emitted compact unwind info for the function, that compact unwind info will | |
| 28 | // be encoded in the __TEXT,__unwind_info section. If the compiler emitted | |
| 29 | // DWARF unwind info, the __TEXT,__unwind_info section will contain the offset | |
| 30 | // of the FDE in the __TEXT,__eh_frame section in the final linked image. | |
| 31 | // | |
| 32 | // Note: Previously, the linker would transform some DWARF unwind infos into | |
| 33 | // compact unwind info. But that is fragile and no longer done. | |
| 34 | ||
| 35 | ||
| 36 | // | |
| 37 | // The compact unwind endoding is a 32-bit value which encoded in an | |
| 38 | // architecture specific way, which registers to restore from where, and how | |
| 39 | // to unwind out of the function. | |
| 40 | // | |
| 41 | typedef uint32_t compact_unwind_encoding_t; | |
| 42 | ||
| 43 | ||
| 44 | // architecture independent bits | |
| 45 | enum { | |
| 46 | UNWIND_IS_NOT_FUNCTION_START = 0x80000000, | |
| 47 | UNWIND_HAS_LSDA = 0x40000000, | |
| 48 | UNWIND_PERSONALITY_MASK = 0x30000000, | |
| 49 | }; | |
| 50 | ||
| 51 | ||
| 52 | ||
| 53 | ||
| 54 | // | |
| 55 | // x86 | |
| 56 | // | |
| 57 | // 1-bit: start | |
| 58 | // 1-bit: has lsda | |
| 59 | // 2-bit: personality index | |
| 60 | // | |
| 61 | // 4-bits: 0=old, 1=ebp based, 2=stack-imm, 3=stack-ind, 4=DWARF | |
| 62 | // ebp based: | |
| 63 | // 15-bits (5*3-bits per reg) register permutation | |
| 64 | // 8-bits for stack offset | |
| 65 | // frameless: | |
| 66 | // 8-bits stack size | |
| 67 | // 3-bits stack adjust | |
| 68 | // 3-bits register count | |
| 69 | // 10-bits register permutation | |
| 70 | // | |
| 71 | enum { | |
| 72 | UNWIND_X86_MODE_MASK = 0x0F000000, | |
| 73 | UNWIND_X86_MODE_EBP_FRAME = 0x01000000, | |
| 74 | UNWIND_X86_MODE_STACK_IMMD = 0x02000000, | |
| 75 | UNWIND_X86_MODE_STACK_IND = 0x03000000, | |
| 76 | UNWIND_X86_MODE_DWARF = 0x04000000, | |
| 77 | ||
| 78 | UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF, | |
| 79 | UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000, | |
| 80 | ||
| 81 | UNWIND_X86_FRAMELESS_STACK_SIZE = 0x00FF0000, | |
| 82 | UNWIND_X86_FRAMELESS_STACK_ADJUST = 0x0000E000, | |
| 83 | UNWIND_X86_FRAMELESS_STACK_REG_COUNT = 0x00001C00, | |
| 84 | UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF, | |
| 85 | ||
| 86 | UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF, | |
| 87 | }; | |
| 88 | ||
| 89 | enum { | |
| 90 | UNWIND_X86_REG_NONE = 0, | |
| 91 | UNWIND_X86_REG_EBX = 1, | |
| 92 | UNWIND_X86_REG_ECX = 2, | |
| 93 | UNWIND_X86_REG_EDX = 3, | |
| 94 | UNWIND_X86_REG_EDI = 4, | |
| 95 | UNWIND_X86_REG_ESI = 5, | |
| 96 | UNWIND_X86_REG_EBP = 6, | |
| 97 | }; | |
| 98 | ||
| 99 | // | |
| 100 | // For x86 there are four modes for the compact unwind encoding: | |
| 101 | // UNWIND_X86_MODE_EBP_FRAME: | |
| 102 | // EBP based frame where EBP is push on stack immediately after return address, | |
| 103 | // then ESP is moved to EBP. Thus, to unwind ESP is restored with the current | |
| 104 | // EPB value, then EBP is restored by popping off the stack, and the return | |
| 105 | // is done by popping the stack once more into the pc. | |
| 106 | // All non-volatile registers that need to be restored must have been saved | |
| 107 | // in a small range in the stack that starts EBP-4 to EBP-1020. The offset/4 | |
| 108 | // is encoded in the UNWIND_X86_EBP_FRAME_OFFSET bits. The registers saved | |
| 109 | // are encoded in the UNWIND_X86_EBP_FRAME_REGISTERS bits as five 3-bit entries. | |
| 110 | // Each entry contains which register to restore. | |
| 111 | // UNWIND_X86_MODE_STACK_IMMD: | |
| 112 | // A "frameless" (EBP not used as frame pointer) function with a small | |
| 113 | // constant stack size. To return, a constant (encoded in the compact | |
| 114 | // unwind encoding) is added to the ESP. Then the return is done by | |
| 115 | // popping the stack into the pc. | |
| 116 | // All non-volatile registers that need to be restored must have been saved | |
| 117 | // on the stack immediately after the return address. The stack_size/4 is | |
| 118 | // encoded in the UNWIND_X86_FRAMELESS_STACK_SIZE (max stack size is 1024). | |
| 119 | // The number of registers saved is encoded in UNWIND_X86_FRAMELESS_STACK_REG_COUNT. | |
| 120 | // UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION constains which registers were | |
| 121 | // saved and their order. | |
| 122 | // UNWIND_X86_MODE_STACK_IND: | |
| 123 | // A "frameless" (EBP not used as frame pointer) function large constant | |
| 124 | // stack size. This case is like the previous, except the stack size is too | |
| 125 | // large to encode in the compact unwind encoding. Instead it requires that | |
| 126 | // the function contains "subl $nnnnnnnn,ESP" in its prolog. The compact | |
| 127 | // encoding contains the offset to the nnnnnnnn value in the function in | |
| 128 | // UNWIND_X86_FRAMELESS_STACK_SIZE. | |
| 129 | // UNWIND_X86_MODE_DWARF: | |
| 130 | // No compact unwind encoding is available. Instead the low 24-bits of the | |
| 131 | // compact encoding is the offset of the DWARF FDE in the __eh_frame section. | |
| 132 | // This mode is never used in object files. It is only generated by the | |
| 133 | // linker in final linked images which have only DWARF unwind info for a | |
| 134 | // function. | |
| 135 | // | |
| 136 | // The permutation encoding is a Lehmer code sequence encoded into a | |
| 137 | // single variable-base number so we can encode the ordering of up to | |
| 138 | // six registers in a 10-bit space. | |
| 139 | // | |
| 140 | // The following is the algorithm used to create the permutation encoding used | |
| 141 | // with frameless stacks. It is passed the number of registers to be saved and | |
| 142 | // an array of the register numbers saved. | |
| 143 | // | |
| 144 | //uint32_t permute_encode(uint32_t registerCount, const uint32_t registers[6]) | |
| 145 | //{ | |
| 146 | // uint32_t renumregs[6]; | |
| 147 | // for (int i=6-registerCount; i < 6; ++i) { | |
| 148 | // int countless = 0; | |
| 149 | // for (int j=6-registerCount; j < i; ++j) { | |
| 150 | // if ( registers[j] < registers[i] ) | |
| 151 | // ++countless; | |
| 152 | // } | |
| 153 | // renumregs[i] = registers[i] - countless -1; | |
| 154 | // } | |
| 155 | // uint32_t permutationEncoding = 0; | |
| 156 | // switch ( registerCount ) { | |
| 157 | // case 6: | |
| 158 | // permutationEncoding |= (120*renumregs[0] + 24*renumregs[1] | |
| 159 | // + 6*renumregs[2] + 2*renumregs[3] | |
| 160 | // + renumregs[4]); | |
| 161 | // break; | |
| 162 | // case 5: | |
| 163 | // permutationEncoding |= (120*renumregs[1] + 24*renumregs[2] | |
| 164 | // + 6*renumregs[3] + 2*renumregs[4] | |
| 165 | // + renumregs[5]); | |
| 166 | // break; | |
| 167 | // case 4: | |
| 168 | // permutationEncoding |= (60*renumregs[2] + 12*renumregs[3] | |
| 169 | // + 3*renumregs[4] + renumregs[5]); | |
| 170 | // break; | |
| 171 | // case 3: | |
| 172 | // permutationEncoding |= (20*renumregs[3] + 4*renumregs[4] | |
| 173 | // + renumregs[5]); | |
| 174 | // break; | |
| 175 | // case 2: | |
| 176 | // permutationEncoding |= (5*renumregs[4] + renumregs[5]); | |
| 177 | // break; | |
| 178 | // case 1: | |
| 179 | // permutationEncoding |= (renumregs[5]); | |
| 180 | // break; | |
| 181 | // } | |
| 182 | // return permutationEncoding; | |
| 183 | //} | |
| 184 | // | |
| 185 | ||
| 186 | ||
| 187 | ||
| 188 | ||
| 189 | // | |
| 190 | // x86_64 | |
| 191 | // | |
| 192 | // 1-bit: start | |
| 193 | // 1-bit: has lsda | |
| 194 | // 2-bit: personality index | |
| 195 | // | |
| 196 | // 4-bits: 0=old, 1=rbp based, 2=stack-imm, 3=stack-ind, 4=DWARF | |
| 197 | // rbp based: | |
| 198 | // 15-bits (5*3-bits per reg) register permutation | |
| 199 | // 8-bits for stack offset | |
| 200 | // frameless: | |
| 201 | // 8-bits stack size | |
| 202 | // 3-bits stack adjust | |
| 203 | // 3-bits register count | |
| 204 | // 10-bits register permutation | |
| 205 | // | |
| 206 | enum { | |
| 207 | UNWIND_X86_64_MODE_MASK = 0x0F000000, | |
| 208 | UNWIND_X86_64_MODE_RBP_FRAME = 0x01000000, | |
| 209 | UNWIND_X86_64_MODE_STACK_IMMD = 0x02000000, | |
| 210 | UNWIND_X86_64_MODE_STACK_IND = 0x03000000, | |
| 211 | UNWIND_X86_64_MODE_DWARF = 0x04000000, | |
| 212 | ||
| 213 | UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF, | |
| 214 | UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000, | |
| 215 | ||
| 216 | UNWIND_X86_64_FRAMELESS_STACK_SIZE = 0x00FF0000, | |
| 217 | UNWIND_X86_64_FRAMELESS_STACK_ADJUST = 0x0000E000, | |
| 218 | UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT = 0x00001C00, | |
| 219 | UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF, | |
| 220 | ||
| 221 | UNWIND_X86_64_DWARF_SECTION_OFFSET = 0x00FFFFFF, | |
| 222 | }; | |
| 223 | ||
| 224 | enum { | |
| 225 | UNWIND_X86_64_REG_NONE = 0, | |
| 226 | UNWIND_X86_64_REG_RBX = 1, | |
| 227 | UNWIND_X86_64_REG_R12 = 2, | |
| 228 | UNWIND_X86_64_REG_R13 = 3, | |
| 229 | UNWIND_X86_64_REG_R14 = 4, | |
| 230 | UNWIND_X86_64_REG_R15 = 5, | |
| 231 | UNWIND_X86_64_REG_RBP = 6, | |
| 232 | }; | |
| 233 | // | |
| 234 | // For x86_64 there are four modes for the compact unwind encoding: | |
| 235 | // UNWIND_X86_64_MODE_RBP_FRAME: | |
| 236 | // RBP based frame where RBP is push on stack immediately after return address, | |
| 237 | // then RSP is moved to RBP. Thus, to unwind RSP is restored with the current | |
| 238 | // EPB value, then RBP is restored by popping off the stack, and the return | |
| 239 | // is done by popping the stack once more into the pc. | |
| 240 | // All non-volatile registers that need to be restored must have been saved | |
| 241 | // in a small range in the stack that starts RBP-8 to RBP-2040. The offset/8 | |
| 242 | // is encoded in the UNWIND_X86_64_RBP_FRAME_OFFSET bits. The registers saved | |
| 243 | // are encoded in the UNWIND_X86_64_RBP_FRAME_REGISTERS bits as five 3-bit entries. | |
| 244 | // Each entry contains which register to restore. | |
| 245 | // UNWIND_X86_64_MODE_STACK_IMMD: | |
| 246 | // A "frameless" (RBP not used as frame pointer) function with a small | |
| 247 | // constant stack size. To return, a constant (encoded in the compact | |
| 248 | // unwind encoding) is added to the RSP. Then the return is done by | |
| 249 | // popping the stack into the pc. | |
| 250 | // All non-volatile registers that need to be restored must have been saved | |
| 251 | // on the stack immediately after the return address. The stack_size/8 is | |
| 252 | // encoded in the UNWIND_X86_64_FRAMELESS_STACK_SIZE (max stack size is 2048). | |
| 253 | // The number of registers saved is encoded in UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT. | |
| 254 | // UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION constains which registers were | |
| 255 | // saved and their order. | |
| 256 | // UNWIND_X86_64_MODE_STACK_IND: | |
| 257 | // A "frameless" (RBP not used as frame pointer) function large constant | |
| 258 | // stack size. This case is like the previous, except the stack size is too | |
| 259 | // large to encode in the compact unwind encoding. Instead it requires that | |
| 260 | // the function contains "subq $nnnnnnnn,RSP" in its prolog. The compact | |
| 261 | // encoding contains the offset to the nnnnnnnn value in the function in | |
| 262 | // UNWIND_X86_64_FRAMELESS_STACK_SIZE. | |
| 263 | // UNWIND_X86_64_MODE_DWARF: | |
| 264 | // No compact unwind encoding is available. Instead the low 24-bits of the | |
| 265 | // compact encoding is the offset of the DWARF FDE in the __eh_frame section. | |
| 266 | // This mode is never used in object files. It is only generated by the | |
| 267 | // linker in final linked images which have only DWARF unwind info for a | |
| 268 | // function. | |
| 269 | // | |
| 270 | ||
| 271 | ||
| 272 | // ARM64 | |
| 273 | // | |
| 274 | // 1-bit: start | |
| 275 | // 1-bit: has lsda | |
| 276 | // 2-bit: personality index | |
| 277 | // | |
| 278 | // 4-bits: 4=frame-based, 3=DWARF, 2=frameless | |
| 279 | // frameless: | |
| 280 | // 12-bits of stack size | |
| 281 | // frame-based: | |
| 282 | // 4-bits D reg pairs saved | |
| 283 | // 5-bits X reg pairs saved | |
| 284 | // DWARF: | |
| 285 | // 24-bits offset of DWARF FDE in __eh_frame section | |
| 286 | // | |
| 287 | enum { | |
| 288 | UNWIND_ARM64_MODE_MASK = 0x0F000000, | |
| 289 | UNWIND_ARM64_MODE_FRAMELESS = 0x02000000, | |
| 290 | UNWIND_ARM64_MODE_DWARF = 0x03000000, | |
| 291 | UNWIND_ARM64_MODE_FRAME = 0x04000000, | |
| 292 | ||
| 293 | UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001, | |
| 294 | UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002, | |
| 295 | UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004, | |
| 296 | UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008, | |
| 297 | UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010, | |
| 298 | UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100, | |
| 299 | UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200, | |
| 300 | UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400, | |
| 301 | UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800, | |
| 302 | ||
| 303 | UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK = 0x00FFF000, | |
| 304 | UNWIND_ARM64_DWARF_SECTION_OFFSET = 0x00FFFFFF, | |
| 305 | }; | |
| 306 | // For arm64 there are three modes for the compact unwind encoding: | |
| 307 | // UNWIND_ARM64_MODE_FRAME: | |
| 308 | // This is a standard arm64 prolog where FP/LR are immediately pushed on the | |
| 309 | // stack, then SP is copied to FP. If there are any non-volatile registers | |
| 310 | // saved, then are copied into the stack frame in pairs in a contiguous | |
| 311 | // range right below the saved FP/LR pair. Any subset of the five X pairs | |
| 312 | // and four D pairs can be saved, but the memory layout must be in register | |
| 313 | // number order. | |
| 314 | // UNWIND_ARM64_MODE_FRAMELESS: | |
| 315 | // A "frameless" leaf function, where FP/LR are not saved. The return address | |
| 316 | // remains in LR throughout the function. If any non-volatile registers | |
| 317 | // are saved, they must be pushed onto the stack before any stack space is | |
| 318 | // allocated for local variables. The stack sized (including any saved | |
| 319 | // non-volatile registers) divided by 16 is encoded in the bits | |
| 320 | // UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK. | |
| 321 | // UNWIND_ARM64_MODE_DWARF: | |
| 322 | // No compact unwind encoding is available. Instead the low 24-bits of the | |
| 323 | // compact encoding is the offset of the DWARF FDE in the __eh_frame section. | |
| 324 | // This mode is never used in object files. It is only generated by the | |
| 325 | // linker in final linked images which have only DWARF unwind info for a | |
| 326 | // function. | |
| 327 | // | |
| 328 | ||
| 329 | ||
| 330 | ||
| 331 | ||
| 332 | ||
| 333 | //////////////////////////////////////////////////////////////////////////////// | |
| 334 | // | |
| 335 | // Relocatable Object Files: __LD,__compact_unwind | |
| 336 | // | |
| 337 | //////////////////////////////////////////////////////////////////////////////// | |
| 338 | ||
| 339 | // | |
| 340 | // A compiler can generated compact unwind information for a function by adding | |
| 341 | // a "row" to the __LD,__compact_unwind section. This section has the | |
| 342 | // S_ATTR_DEBUG bit set, so the section will be ignored by older linkers. | |
| 343 | // It is removed by the new linker, so never ends up in final executables. | |
| 344 | // This section is a table, initially with one row per function (that needs | |
| 345 | // unwind info). The table columns and some conceptual entries are: | |
| 346 | // | |
| 347 | // range-start pointer to start of function/range | |
| 348 | // range-length | |
| 349 | // compact-unwind-encoding 32-bit encoding | |
| 350 | // personality-function or zero if no personality function | |
| 351 | // lsda or zero if no LSDA data | |
| 352 | // | |
| 353 | // The length and encoding fields are 32-bits. The other are all pointer sized. | |
| 354 | // | |
| 355 | // In x86_64 assembly, these entry would look like: | |
| 356 | // | |
| 357 | // .section __LD,__compact_unwind,regular,debug | |
| 358 | // | |
| 359 | // #compact unwind for _foo | |
| 360 | // .quad _foo | |
| 361 | // .set L1,LfooEnd-_foo | |
| 362 | // .long L1 | |
| 363 | // .long 0x01010001 | |
| 364 | // .quad 0 | |
| 365 | // .quad 0 | |
| 366 | // | |
| 367 | // #compact unwind for _bar | |
| 368 | // .quad _bar | |
| 369 | // .set L2,LbarEnd-_bar | |
| 370 | // .long L2 | |
| 371 | // .long 0x01020011 | |
| 372 | // .quad __gxx_personality | |
| 373 | // .quad except_tab1 | |
| 374 | // | |
| 375 | // | |
| 376 | // Notes: There is no need for any labels in the the __compact_unwind section. | |
| 377 | // The use of the .set directive is to force the evaluation of the | |
| 378 | // range-length at assembly time, instead of generating relocations. | |
| 379 | // | |
| 380 | // To support future compiler optimizations where which non-volatile registers | |
| 381 | // are saved changes within a function (e.g. delay saving non-volatiles until | |
| 382 | // necessary), there can by multiple lines in the __compact_unwind table for one | |
| 383 | // function, each with a different (non-overlapping) range and each with | |
| 384 | // different compact unwind encodings that correspond to the non-volatiles | |
| 385 | // saved at that range of the function. | |
| 386 | // | |
| 387 | // If a particular function is so wacky that there is no compact unwind way | |
| 388 | // to encode it, then the compiler can emit traditional DWARF unwind info. | |
| 389 | // The runtime will use which ever is available. | |
| 390 | // | |
| 391 | // Runtime support for compact unwind encodings are only available on 10.6 | |
| 392 | // and later. So, the compiler should not generate it when targeting pre-10.6. | |
| 393 | ||
| 394 | ||
| 395 | ||
| 396 | ||
| 397 | //////////////////////////////////////////////////////////////////////////////// | |
| 398 | // | |
| 399 | // Final Linked Images: __TEXT,__unwind_info | |
| 400 | // | |
| 401 | //////////////////////////////////////////////////////////////////////////////// | |
| 402 | ||
| 403 | // | |
| 404 | // The __TEXT,__unwind_info section is laid out for an efficient two level lookup. | |
| 405 | // The header of the section contains a coarse index that maps function address | |
| 406 | // to the page (4096 byte block) containing the unwind info for that function. | |
| 407 | // | |
| 408 | ||
| 409 | #define UNWIND_SECTION_VERSION 1 | |
| 410 | struct unwind_info_section_header | |
| 411 | { | |
| 412 | uint32_t version; // UNWIND_SECTION_VERSION | |
| 413 | uint32_t commonEncodingsArraySectionOffset; | |
| 414 | uint32_t commonEncodingsArrayCount; | |
| 415 | uint32_t personalityArraySectionOffset; | |
| 416 | uint32_t personalityArrayCount; | |
| 417 | uint32_t indexSectionOffset; | |
| 418 | uint32_t indexCount; | |
| 419 | // compact_unwind_encoding_t[] | |
| 420 | // uint32_t personalities[] | |
| 421 | // unwind_info_section_header_index_entry[] | |
| 422 | // unwind_info_section_header_lsda_index_entry[] | |
| 423 | }; | |
| 424 | ||
| 425 | struct unwind_info_section_header_index_entry | |
| 426 | { | |
| 427 | uint32_t functionOffset; | |
| 428 | uint32_t secondLevelPagesSectionOffset; // section offset to start of regular or compress page | |
| 429 | uint32_t lsdaIndexArraySectionOffset; // section offset to start of lsda_index array for this range | |
| 430 | }; | |
| 431 | ||
| 432 | struct unwind_info_section_header_lsda_index_entry | |
| 433 | { | |
| 434 | uint32_t functionOffset; | |
| 435 | uint32_t lsdaOffset; | |
| 436 | }; | |
| 437 | ||
| 438 | // | |
| 439 | // There are two kinds of second level index pages: regular and compressed. | |
| 440 | // A compressed page can hold up to 1021 entries, but it cannot be used | |
| 441 | // if too many different encoding types are used. The regular page holds | |
| 442 | // 511 entries. | |
| 443 | // | |
| 444 | ||
| 445 | struct unwind_info_regular_second_level_entry | |
| 446 | { | |
| 447 | uint32_t functionOffset; | |
| 448 | compact_unwind_encoding_t encoding; | |
| 449 | }; | |
| 450 | ||
| 451 | #define UNWIND_SECOND_LEVEL_REGULAR 2 | |
| 452 | struct unwind_info_regular_second_level_page_header | |
| 453 | { | |
| 454 | uint32_t kind; // UNWIND_SECOND_LEVEL_REGULAR | |
| 455 | uint16_t entryPageOffset; | |
| 456 | uint16_t entryCount; | |
| 457 | // entry array | |
| 458 | }; | |
| 459 | ||
| 460 | #define UNWIND_SECOND_LEVEL_COMPRESSED 3 | |
| 461 | struct unwind_info_compressed_second_level_page_header | |
| 462 | { | |
| 463 | uint32_t kind; // UNWIND_SECOND_LEVEL_COMPRESSED | |
| 464 | uint16_t entryPageOffset; | |
| 465 | uint16_t entryCount; | |
| 466 | uint16_t encodingsPageOffset; | |
| 467 | uint16_t encodingsCount; | |
| 468 | // 32-bit entry array | |
| 469 | // encodings array | |
| 470 | }; | |
| 471 | ||
| 472 | #define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry) (entry & 0x00FFFFFF) | |
| 473 | #define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry) ((entry >> 24) & 0xFF) | |
| 474 | ||
| 475 | ||
| 476 | ||
| 477 | #endif | |
| 478 |
libunwind/include/unwind.h created+401| ... | ... | @@ -0,0 +1,401 @@ |
| 1 | //===------------------------------- unwind.h -----------------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is dual licensed under the MIT and the University of Illinois Open | |
| 6 | // Source Licenses. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | // | |
| 9 | // C++ ABI Level 1 ABI documented at: | |
| 10 | // http://mentorembedded.github.io/cxx-abi/abi-eh.html | |
| 11 | // | |
| 12 | //===----------------------------------------------------------------------===// | |
| 13 | ||
| 14 | #ifndef __UNWIND_H__ | |
| 15 | #define __UNWIND_H__ | |
| 16 | ||
| 17 | #include <__libunwind_config.h> | |
| 18 | ||
| 19 | #include <stdint.h> | |
| 20 | #include <stddef.h> | |
| 21 | ||
| 22 | #if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) && defined(_WIN32) | |
| 23 | #include <windows.h> | |
| 24 | #include <ntverp.h> | |
| 25 | #endif | |
| 26 | ||
| 27 | #if defined(__APPLE__) | |
| 28 | #define LIBUNWIND_UNAVAIL __attribute__ (( unavailable )) | |
| 29 | #else | |
| 30 | #define LIBUNWIND_UNAVAIL | |
| 31 | #endif | |
| 32 | ||
| 33 | typedef enum { | |
| 34 | _URC_NO_REASON = 0, | |
| 35 | _URC_OK = 0, | |
| 36 | _URC_FOREIGN_EXCEPTION_CAUGHT = 1, | |
| 37 | _URC_FATAL_PHASE2_ERROR = 2, | |
| 38 | _URC_FATAL_PHASE1_ERROR = 3, | |
| 39 | _URC_NORMAL_STOP = 4, | |
| 40 | _URC_END_OF_STACK = 5, | |
| 41 | _URC_HANDLER_FOUND = 6, | |
| 42 | _URC_INSTALL_CONTEXT = 7, | |
| 43 | _URC_CONTINUE_UNWIND = 8, | |
| 44 | #if defined(_LIBUNWIND_ARM_EHABI) | |
| 45 | _URC_FAILURE = 9 | |
| 46 | #endif | |
| 47 | } _Unwind_Reason_Code; | |
| 48 | ||
| 49 | typedef enum { | |
| 50 | _UA_SEARCH_PHASE = 1, | |
| 51 | _UA_CLEANUP_PHASE = 2, | |
| 52 | _UA_HANDLER_FRAME = 4, | |
| 53 | _UA_FORCE_UNWIND = 8, | |
| 54 | _UA_END_OF_STACK = 16 // gcc extension to C++ ABI | |
| 55 | } _Unwind_Action; | |
| 56 | ||
| 57 | typedef struct _Unwind_Context _Unwind_Context; // opaque | |
| 58 | ||
| 59 | #if defined(_LIBUNWIND_ARM_EHABI) | |
| 60 | typedef uint32_t _Unwind_State; | |
| 61 | ||
| 62 | static const _Unwind_State _US_VIRTUAL_UNWIND_FRAME = 0; | |
| 63 | static const _Unwind_State _US_UNWIND_FRAME_STARTING = 1; | |
| 64 | static const _Unwind_State _US_UNWIND_FRAME_RESUME = 2; | |
| 65 | static const _Unwind_State _US_ACTION_MASK = 3; | |
| 66 | /* Undocumented flag for force unwinding. */ | |
| 67 | static const _Unwind_State _US_FORCE_UNWIND = 8; | |
| 68 | ||
| 69 | typedef uint32_t _Unwind_EHT_Header; | |
| 70 | ||
| 71 | struct _Unwind_Control_Block; | |
| 72 | typedef struct _Unwind_Control_Block _Unwind_Control_Block; | |
| 73 | typedef struct _Unwind_Control_Block _Unwind_Exception; /* Alias */ | |
| 74 | ||
| 75 | struct _Unwind_Control_Block { | |
| 76 | uint64_t exception_class; | |
| 77 | void (*exception_cleanup)(_Unwind_Reason_Code, _Unwind_Control_Block*); | |
| 78 | ||
| 79 | /* Unwinder cache, private fields for the unwinder's use */ | |
| 80 | struct { | |
| 81 | uint32_t reserved1; /* init reserved1 to 0, then don't touch */ | |
| 82 | uint32_t reserved2; | |
| 83 | uint32_t reserved3; | |
| 84 | uint32_t reserved4; | |
| 85 | uint32_t reserved5; | |
| 86 | } unwinder_cache; | |
| 87 | ||
| 88 | /* Propagation barrier cache (valid after phase 1): */ | |
| 89 | struct { | |
| 90 | uint32_t sp; | |
| 91 | uint32_t bitpattern[5]; | |
| 92 | } barrier_cache; | |
| 93 | ||
| 94 | /* Cleanup cache (preserved over cleanup): */ | |
| 95 | struct { | |
| 96 | uint32_t bitpattern[4]; | |
| 97 | } cleanup_cache; | |
| 98 | ||
| 99 | /* Pr cache (for pr's benefit): */ | |
| 100 | struct { | |
| 101 | uint32_t fnstart; /* function start address */ | |
| 102 | _Unwind_EHT_Header* ehtp; /* pointer to EHT entry header word */ | |
| 103 | uint32_t additional; | |
| 104 | uint32_t reserved1; | |
| 105 | } pr_cache; | |
| 106 | ||
| 107 | long long int :0; /* Enforce the 8-byte alignment */ | |
| 108 | } __attribute__((__aligned__(8))); | |
| 109 | ||
| 110 | typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) | |
| 111 | (_Unwind_State state, | |
| 112 | _Unwind_Exception* exceptionObject, | |
| 113 | struct _Unwind_Context* context); | |
| 114 | ||
| 115 | typedef _Unwind_Reason_Code (*__personality_routine) | |
| 116 | (_Unwind_State state, | |
| 117 | _Unwind_Exception* exceptionObject, | |
| 118 | struct _Unwind_Context* context); | |
| 119 | #else | |
| 120 | struct _Unwind_Context; // opaque | |
| 121 | struct _Unwind_Exception; // forward declaration | |
| 122 | typedef struct _Unwind_Exception _Unwind_Exception; | |
| 123 | ||
| 124 | struct _Unwind_Exception { | |
| 125 | uint64_t exception_class; | |
| 126 | void (*exception_cleanup)(_Unwind_Reason_Code reason, | |
| 127 | _Unwind_Exception *exc); | |
| 128 | #if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) | |
| 129 | uintptr_t private_[6]; | |
| 130 | #else | |
| 131 | uintptr_t private_1; // non-zero means forced unwind | |
| 132 | uintptr_t private_2; // holds sp that phase1 found for phase2 to use | |
| 133 | #endif | |
| 134 | #if __SIZEOF_POINTER__ == 4 | |
| 135 | // The implementation of _Unwind_Exception uses an attribute mode on the | |
| 136 | // above fields which has the side effect of causing this whole struct to | |
| 137 | // round up to 32 bytes in size (48 with SEH). To be more explicit, we add | |
| 138 | // pad fields added for binary compatibility. | |
| 139 | uint32_t reserved[3]; | |
| 140 | #endif | |
| 141 | // The Itanium ABI requires that _Unwind_Exception objects are "double-word | |
| 142 | // aligned". GCC has interpreted this to mean "use the maximum useful | |
| 143 | // alignment for the target"; so do we. | |
| 144 | } __attribute__((__aligned__)); | |
| 145 | ||
| 146 | typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) | |
| 147 | (int version, | |
| 148 | _Unwind_Action actions, | |
| 149 | uint64_t exceptionClass, | |
| 150 | _Unwind_Exception* exceptionObject, | |
| 151 | struct _Unwind_Context* context, | |
| 152 | void* stop_parameter ); | |
| 153 | ||
| 154 | typedef _Unwind_Reason_Code (*__personality_routine) | |
| 155 | (int version, | |
| 156 | _Unwind_Action actions, | |
| 157 | uint64_t exceptionClass, | |
| 158 | _Unwind_Exception* exceptionObject, | |
| 159 | struct _Unwind_Context* context); | |
| 160 | #endif | |
| 161 | ||
| 162 | #ifdef __cplusplus | |
| 163 | extern "C" { | |
| 164 | #endif | |
| 165 | ||
| 166 | // | |
| 167 | // The following are the base functions documented by the C++ ABI | |
| 168 | // | |
| 169 | #ifdef __USING_SJLJ_EXCEPTIONS__ | |
| 170 | extern _Unwind_Reason_Code | |
| 171 | _Unwind_SjLj_RaiseException(_Unwind_Exception *exception_object); | |
| 172 | extern void _Unwind_SjLj_Resume(_Unwind_Exception *exception_object); | |
| 173 | #else | |
| 174 | extern _Unwind_Reason_Code | |
| 175 | _Unwind_RaiseException(_Unwind_Exception *exception_object); | |
| 176 | extern void _Unwind_Resume(_Unwind_Exception *exception_object); | |
| 177 | #endif | |
| 178 | extern void _Unwind_DeleteException(_Unwind_Exception *exception_object); | |
| 179 | ||
| 180 | #if defined(_LIBUNWIND_ARM_EHABI) | |
| 181 | typedef enum { | |
| 182 | _UVRSC_CORE = 0, /* integer register */ | |
| 183 | _UVRSC_VFP = 1, /* vfp */ | |
| 184 | _UVRSC_WMMXD = 3, /* Intel WMMX data register */ | |
| 185 | _UVRSC_WMMXC = 4 /* Intel WMMX control register */ | |
| 186 | } _Unwind_VRS_RegClass; | |
| 187 | ||
| 188 | typedef enum { | |
| 189 | _UVRSD_UINT32 = 0, | |
| 190 | _UVRSD_VFPX = 1, | |
| 191 | _UVRSD_UINT64 = 3, | |
| 192 | _UVRSD_FLOAT = 4, | |
| 193 | _UVRSD_DOUBLE = 5 | |
| 194 | } _Unwind_VRS_DataRepresentation; | |
| 195 | ||
| 196 | typedef enum { | |
| 197 | _UVRSR_OK = 0, | |
| 198 | _UVRSR_NOT_IMPLEMENTED = 1, | |
| 199 | _UVRSR_FAILED = 2 | |
| 200 | } _Unwind_VRS_Result; | |
| 201 | ||
| 202 | extern void _Unwind_Complete(_Unwind_Exception* exception_object); | |
| 203 | ||
| 204 | extern _Unwind_VRS_Result | |
| 205 | _Unwind_VRS_Get(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, | |
| 206 | uint32_t regno, _Unwind_VRS_DataRepresentation representation, | |
| 207 | void *valuep); | |
| 208 | ||
| 209 | extern _Unwind_VRS_Result | |
| 210 | _Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, | |
| 211 | uint32_t regno, _Unwind_VRS_DataRepresentation representation, | |
| 212 | void *valuep); | |
| 213 | ||
| 214 | extern _Unwind_VRS_Result | |
| 215 | _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, | |
| 216 | uint32_t discriminator, | |
| 217 | _Unwind_VRS_DataRepresentation representation); | |
| 218 | #endif | |
| 219 | ||
| 220 | #if !defined(_LIBUNWIND_ARM_EHABI) | |
| 221 | ||
| 222 | extern uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index); | |
| 223 | extern void _Unwind_SetGR(struct _Unwind_Context *context, int index, | |
| 224 | uintptr_t new_value); | |
| 225 | extern uintptr_t _Unwind_GetIP(struct _Unwind_Context *context); | |
| 226 | extern void _Unwind_SetIP(struct _Unwind_Context *, uintptr_t new_value); | |
| 227 | ||
| 228 | #else // defined(_LIBUNWIND_ARM_EHABI) | |
| 229 | ||
| 230 | #if defined(_LIBUNWIND_UNWIND_LEVEL1_EXTERNAL_LINKAGE) | |
| 231 | #define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 extern | |
| 232 | #else | |
| 233 | #define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 static __inline__ | |
| 234 | #endif | |
| 235 | ||
| 236 | // These are de facto helper functions for ARM, which delegate the function | |
| 237 | // calls to _Unwind_VRS_Get/Set(). These are not a part of ARM EHABI | |
| 238 | // specification, thus these function MUST be inlined. Please don't replace | |
| 239 | // these with the "extern" function declaration; otherwise, the program | |
| 240 | // including this <unwind.h> header won't be ABI compatible and will result in | |
| 241 | // link error when we are linking the program with libgcc. | |
| 242 | ||
| 243 | _LIBUNWIND_EXPORT_UNWIND_LEVEL1 | |
| 244 | uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index) { | |
| 245 | uintptr_t value = 0; | |
| 246 | _Unwind_VRS_Get(context, _UVRSC_CORE, (uint32_t)index, _UVRSD_UINT32, &value); | |
| 247 | return value; | |
| 248 | } | |
| 249 | ||
| 250 | _LIBUNWIND_EXPORT_UNWIND_LEVEL1 | |
| 251 | void _Unwind_SetGR(struct _Unwind_Context *context, int index, | |
| 252 | uintptr_t value) { | |
| 253 | _Unwind_VRS_Set(context, _UVRSC_CORE, (uint32_t)index, _UVRSD_UINT32, &value); | |
| 254 | } | |
| 255 | ||
| 256 | _LIBUNWIND_EXPORT_UNWIND_LEVEL1 | |
| 257 | uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) { | |
| 258 | // remove the thumb-bit before returning | |
| 259 | return _Unwind_GetGR(context, 15) & (~(uintptr_t)0x1); | |
| 260 | } | |
| 261 | ||
| 262 | _LIBUNWIND_EXPORT_UNWIND_LEVEL1 | |
| 263 | void _Unwind_SetIP(struct _Unwind_Context *context, uintptr_t value) { | |
| 264 | uintptr_t thumb_bit = _Unwind_GetGR(context, 15) & ((uintptr_t)0x1); | |
| 265 | _Unwind_SetGR(context, 15, value | thumb_bit); | |
| 266 | } | |
| 267 | #endif // defined(_LIBUNWIND_ARM_EHABI) | |
| 268 | ||
| 269 | extern uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context *context); | |
| 270 | extern uintptr_t | |
| 271 | _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context); | |
| 272 | #ifdef __USING_SJLJ_EXCEPTIONS__ | |
| 273 | extern _Unwind_Reason_Code | |
| 274 | _Unwind_SjLj_ForcedUnwind(_Unwind_Exception *exception_object, | |
| 275 | _Unwind_Stop_Fn stop, void *stop_parameter); | |
| 276 | #else | |
| 277 | extern _Unwind_Reason_Code | |
| 278 | _Unwind_ForcedUnwind(_Unwind_Exception *exception_object, | |
| 279 | _Unwind_Stop_Fn stop, void *stop_parameter); | |
| 280 | #endif | |
| 281 | ||
| 282 | #ifdef __USING_SJLJ_EXCEPTIONS__ | |
| 283 | typedef struct _Unwind_FunctionContext *_Unwind_FunctionContext_t; | |
| 284 | extern void _Unwind_SjLj_Register(_Unwind_FunctionContext_t fc); | |
| 285 | extern void _Unwind_SjLj_Unregister(_Unwind_FunctionContext_t fc); | |
| 286 | #endif | |
| 287 | ||
| 288 | // | |
| 289 | // The following are semi-suppoted extensions to the C++ ABI | |
| 290 | // | |
| 291 | ||
| 292 | // | |
| 293 | // called by __cxa_rethrow(). | |
| 294 | // | |
| 295 | #ifdef __USING_SJLJ_EXCEPTIONS__ | |
| 296 | extern _Unwind_Reason_Code | |
| 297 | _Unwind_SjLj_Resume_or_Rethrow(_Unwind_Exception *exception_object); | |
| 298 | #else | |
| 299 | extern _Unwind_Reason_Code | |
| 300 | _Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object); | |
| 301 | #endif | |
| 302 | ||
| 303 | // _Unwind_Backtrace() is a gcc extension that walks the stack and calls the | |
| 304 | // _Unwind_Trace_Fn once per frame until it reaches the bottom of the stack | |
| 305 | // or the _Unwind_Trace_Fn function returns something other than _URC_NO_REASON. | |
| 306 | typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context *, | |
| 307 | void *); | |
| 308 | extern _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void *); | |
| 309 | ||
| 310 | // _Unwind_GetCFA is a gcc extension that can be called from within a | |
| 311 | // personality handler to get the CFA (stack pointer before call) of | |
| 312 | // current frame. | |
| 313 | extern uintptr_t _Unwind_GetCFA(struct _Unwind_Context *); | |
| 314 | ||
| 315 | ||
| 316 | // _Unwind_GetIPInfo is a gcc extension that can be called from within a | |
| 317 | // personality handler. Similar to _Unwind_GetIP() but also returns in | |
| 318 | // *ipBefore a non-zero value if the instruction pointer is at or before the | |
| 319 | // instruction causing the unwind. Normally, in a function call, the IP returned | |
| 320 | // is the return address which is after the call instruction and may be past the | |
| 321 | // end of the function containing the call instruction. | |
| 322 | extern uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context, | |
| 323 | int *ipBefore); | |
| 324 | ||
| 325 | ||
| 326 | // __register_frame() is used with dynamically generated code to register the | |
| 327 | // FDE for a generated (JIT) code. The FDE must use pc-rel addressing to point | |
| 328 | // to its function and optional LSDA. | |
| 329 | // __register_frame() has existed in all versions of Mac OS X, but in 10.4 and | |
| 330 | // 10.5 it was buggy and did not actually register the FDE with the unwinder. | |
| 331 | // In 10.6 and later it does register properly. | |
| 332 | extern void __register_frame(const void *fde); | |
| 333 | extern void __deregister_frame(const void *fde); | |
| 334 | ||
| 335 | // _Unwind_Find_FDE() will locate the FDE if the pc is in some function that has | |
| 336 | // an associated FDE. Note, Mac OS X 10.6 and later, introduces "compact unwind | |
| 337 | // info" which the runtime uses in preference to DWARF unwind info. This | |
| 338 | // function will only work if the target function has an FDE but no compact | |
| 339 | // unwind info. | |
| 340 | struct dwarf_eh_bases { | |
| 341 | uintptr_t tbase; | |
| 342 | uintptr_t dbase; | |
| 343 | uintptr_t func; | |
| 344 | }; | |
| 345 | extern const void *_Unwind_Find_FDE(const void *pc, struct dwarf_eh_bases *); | |
| 346 | ||
| 347 | ||
| 348 | // This function attempts to find the start (address of first instruction) of | |
| 349 | // a function given an address inside the function. It only works if the | |
| 350 | // function has an FDE (DWARF unwind info). | |
| 351 | // This function is unimplemented on Mac OS X 10.6 and later. Instead, use | |
| 352 | // _Unwind_Find_FDE() and look at the dwarf_eh_bases.func result. | |
| 353 | extern void *_Unwind_FindEnclosingFunction(void *pc); | |
| 354 | ||
| 355 | // Mac OS X does not support text-rel and data-rel addressing so these functions | |
| 356 | // are unimplemented | |
| 357 | extern uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context *context) | |
| 358 | LIBUNWIND_UNAVAIL; | |
| 359 | extern uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context *context) | |
| 360 | LIBUNWIND_UNAVAIL; | |
| 361 | ||
| 362 | // Mac OS X 10.4 and 10.5 had implementations of these functions in | |
| 363 | // libgcc_s.dylib, but they never worked. | |
| 364 | /// These functions are no longer available on Mac OS X. | |
| 365 | extern void __register_frame_info_bases(const void *fde, void *ob, void *tb, | |
| 366 | void *db) LIBUNWIND_UNAVAIL; | |
| 367 | extern void __register_frame_info(const void *fde, void *ob) | |
| 368 | LIBUNWIND_UNAVAIL; | |
| 369 | extern void __register_frame_info_table_bases(const void *fde, void *ob, | |
| 370 | void *tb, void *db) | |
| 371 | LIBUNWIND_UNAVAIL; | |
| 372 | extern void __register_frame_info_table(const void *fde, void *ob) | |
| 373 | LIBUNWIND_UNAVAIL; | |
| 374 | extern void __register_frame_table(const void *fde) | |
| 375 | LIBUNWIND_UNAVAIL; | |
| 376 | extern void *__deregister_frame_info(const void *fde) | |
| 377 | LIBUNWIND_UNAVAIL; | |
| 378 | extern void *__deregister_frame_info_bases(const void *fde) | |
| 379 | LIBUNWIND_UNAVAIL; | |
| 380 | ||
| 381 | #if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) | |
| 382 | #ifndef _WIN32 | |
| 383 | typedef struct _EXCEPTION_RECORD EXCEPTION_RECORD; | |
| 384 | typedef struct _CONTEXT CONTEXT; | |
| 385 | typedef struct _DISPATCHER_CONTEXT DISPATCHER_CONTEXT; | |
| 386 | #elif !defined(__MINGW32__) && VER_PRODUCTBUILD < 8000 | |
| 387 | typedef struct _DISPATCHER_CONTEXT DISPATCHER_CONTEXT; | |
| 388 | #endif | |
| 389 | // This is the common wrapper for GCC-style personality functions with SEH. | |
| 390 | extern EXCEPTION_DISPOSITION _GCC_specific_handler(EXCEPTION_RECORD *exc, | |
| 391 | void *frame, | |
| 392 | CONTEXT *ctx, | |
| 393 | DISPATCHER_CONTEXT *disp, | |
| 394 | __personality_routine pers); | |
| 395 | #endif | |
| 396 | ||
| 397 | #ifdef __cplusplus | |
| 398 | } | |
| 399 | #endif | |
| 400 | ||
| 401 | #endif // __UNWIND_H__ |
libunwind/src/AddressSpace.hpp created+738| ... | ... | @@ -0,0 +1,738 @@ |
| 1 | //===------------------------- AddressSpace.hpp ---------------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is dual licensed under the MIT and the University of Illinois Open | |
| 6 | // Source Licenses. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | // | |
| 9 | // Abstracts accessing local vs remote address spaces. | |
| 10 | // | |
| 11 | //===----------------------------------------------------------------------===// | |
| 12 | ||
| 13 | #ifndef __ADDRESSSPACE_HPP__ | |
| 14 | #define __ADDRESSSPACE_HPP__ | |
| 15 | ||
| 16 | #include <stdint.h> | |
| 17 | #include <stdio.h> | |
| 18 | #include <stdlib.h> | |
| 19 | #include <string.h> | |
| 20 | ||
| 21 | #ifndef _LIBUNWIND_USE_DLADDR | |
| 22 | #if !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32) | |
| 23 | #define _LIBUNWIND_USE_DLADDR 1 | |
| 24 | #else | |
| 25 | #define _LIBUNWIND_USE_DLADDR 0 | |
| 26 | #endif | |
| 27 | #endif | |
| 28 | ||
| 29 | #if _LIBUNWIND_USE_DLADDR | |
| 30 | #include <dlfcn.h> | |
| 31 | #endif | |
| 32 | ||
| 33 | #ifdef __APPLE__ | |
| 34 | #include <mach-o/getsect.h> | |
| 35 | namespace libunwind { | |
| 36 | bool checkKeyMgrRegisteredFDEs(uintptr_t targetAddr, void *&fde); | |
| 37 | } | |
| 38 | #endif | |
| 39 | ||
| 40 | #include "libunwind.h" | |
| 41 | #include "config.h" | |
| 42 | #include "dwarf2.h" | |
| 43 | #include "EHHeaderParser.hpp" | |
| 44 | #include "Registers.hpp" | |
| 45 | ||
| 46 | #ifdef __APPLE__ | |
| 47 | ||
| 48 | struct dyld_unwind_sections | |
| 49 | { | |
| 50 | const struct mach_header* mh; | |
| 51 | const void* dwarf_section; | |
| 52 | uintptr_t dwarf_section_length; | |
| 53 | const void* compact_unwind_section; | |
| 54 | uintptr_t compact_unwind_section_length; | |
| 55 | }; | |
| 56 | #if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \ | |
| 57 | && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) \ | |
| 58 | || defined(__IPHONE_OS_VERSION_MIN_REQUIRED) | |
| 59 | // In 10.7.0 or later, libSystem.dylib implements this function. | |
| 60 | extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *); | |
| 61 | #else | |
| 62 | // In 10.6.x and earlier, we need to implement this functionality. Note | |
| 63 | // that this requires a newer version of libmacho (from cctools) than is | |
| 64 | // present in libSystem on 10.6.x (for getsectiondata). | |
| 65 | static inline bool _dyld_find_unwind_sections(void* addr, | |
| 66 | dyld_unwind_sections* info) { | |
| 67 | // Find mach-o image containing address. | |
| 68 | Dl_info dlinfo; | |
| 69 | if (!dladdr(addr, &dlinfo)) | |
| 70 | return false; | |
| 71 | #if __LP64__ | |
| 72 | const struct mach_header_64 *mh = (const struct mach_header_64 *)dlinfo.dli_fbase; | |
| 73 | #else | |
| 74 | const struct mach_header *mh = (const struct mach_header *)dlinfo.dli_fbase; | |
| 75 | #endif | |
| 76 | ||
| 77 | // Initialize the return struct | |
| 78 | info->mh = (const struct mach_header *)mh; | |
| 79 | info->dwarf_section = getsectiondata(mh, "__TEXT", "__eh_frame", &info->dwarf_section_length); | |
| 80 | info->compact_unwind_section = getsectiondata(mh, "__TEXT", "__unwind_info", &info->compact_unwind_section_length); | |
| 81 | ||
| 82 | if (!info->dwarf_section) { | |
| 83 | info->dwarf_section_length = 0; | |
| 84 | } | |
| 85 | ||
| 86 | if (!info->compact_unwind_section) { | |
| 87 | info->compact_unwind_section_length = 0; | |
| 88 | } | |
| 89 | ||
| 90 | return true; | |
| 91 | } | |
| 92 | #endif | |
| 93 | ||
| 94 | #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL) | |
| 95 | ||
| 96 | // When statically linked on bare-metal, the symbols for the EH table are looked | |
| 97 | // up without going through the dynamic loader. | |
| 98 | ||
| 99 | // The following linker script may be used to produce the necessary sections and symbols. | |
| 100 | // Unless the --eh-frame-hdr linker option is provided, the section is not generated | |
| 101 | // and does not take space in the output file. | |
| 102 | // | |
| 103 | // .eh_frame : | |
| 104 | // { | |
| 105 | // __eh_frame_start = .; | |
| 106 | // KEEP(*(.eh_frame)) | |
| 107 | // __eh_frame_end = .; | |
| 108 | // } | |
| 109 | // | |
| 110 | // .eh_frame_hdr : | |
| 111 | // { | |
| 112 | // KEEP(*(.eh_frame_hdr)) | |
| 113 | // } | |
| 114 | // | |
| 115 | // __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0; | |
| 116 | // __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0; | |
| 117 | ||
| 118 | extern char __eh_frame_start; | |
| 119 | extern char __eh_frame_end; | |
| 120 | ||
| 121 | #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) | |
| 122 | extern char __eh_frame_hdr_start; | |
| 123 | extern char __eh_frame_hdr_end; | |
| 124 | #endif | |
| 125 | ||
| 126 | #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL) | |
| 127 | ||
| 128 | // When statically linked on bare-metal, the symbols for the EH table are looked | |
| 129 | // up without going through the dynamic loader. | |
| 130 | extern char __exidx_start; | |
| 131 | extern char __exidx_end; | |
| 132 | ||
| 133 | #elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) | |
| 134 | ||
| 135 | // ELF-based systems may use dl_iterate_phdr() to access sections | |
| 136 | // containing unwinding information. The ElfW() macro for pointer-size | |
| 137 | // independent ELF header traversal is not provided by <link.h> on some | |
| 138 | // systems (e.g., FreeBSD). On these systems the data structures are | |
| 139 | // just called Elf_XXX. Define ElfW() locally. | |
| 140 | #ifndef _WIN32 | |
| 141 | #include <link.h> | |
| 142 | #else | |
| 143 | #include <windows.h> | |
| 144 | #include <psapi.h> | |
| 145 | #endif | |
| 146 | #if !defined(ElfW) | |
| 147 | #define ElfW(type) Elf_##type | |
| 148 | #endif | |
| 149 | ||
| 150 | #endif | |
| 151 | ||
| 152 | namespace libunwind { | |
| 153 | ||
| 154 | /// Used by findUnwindSections() to return info about needed sections. | |
| 155 | struct UnwindInfoSections { | |
| 156 | #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) || \ | |
| 157 | defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) | |
| 158 | // No dso_base for SEH or ARM EHABI. | |
| 159 | uintptr_t dso_base; | |
| 160 | #endif | |
| 161 | #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) | |
| 162 | uintptr_t dwarf_section; | |
| 163 | uintptr_t dwarf_section_length; | |
| 164 | #endif | |
| 165 | #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) | |
| 166 | uintptr_t dwarf_index_section; | |
| 167 | uintptr_t dwarf_index_section_length; | |
| 168 | #endif | |
| 169 | #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) | |
| 170 | uintptr_t compact_unwind_section; | |
| 171 | uintptr_t compact_unwind_section_length; | |
| 172 | #endif | |
| 173 | #if defined(_LIBUNWIND_ARM_EHABI) | |
| 174 | uintptr_t arm_section; | |
| 175 | uintptr_t arm_section_length; | |
| 176 | #endif | |
| 177 | }; | |
| 178 | ||
| 179 | ||
| 180 | /// LocalAddressSpace is used as a template parameter to UnwindCursor when | |
| 181 | /// unwinding a thread in the same process. The wrappers compile away, | |
| 182 | /// making local unwinds fast. | |
| 183 | class _LIBUNWIND_HIDDEN LocalAddressSpace { | |
| 184 | public: | |
| 185 | typedef uintptr_t pint_t; | |
| 186 | typedef intptr_t sint_t; | |
| 187 | uint8_t get8(pint_t addr) { | |
| 188 | uint8_t val; | |
| 189 | memcpy(&val, (void *)addr, sizeof(val)); | |
| 190 | return val; | |
| 191 | } | |
| 192 | uint16_t get16(pint_t addr) { | |
| 193 | uint16_t val; | |
| 194 | memcpy(&val, (void *)addr, sizeof(val)); | |
| 195 | return val; | |
| 196 | } | |
| 197 | uint32_t get32(pint_t addr) { | |
| 198 | uint32_t val; | |
| 199 | memcpy(&val, (void *)addr, sizeof(val)); | |
| 200 | return val; | |
| 201 | } | |
| 202 | uint64_t get64(pint_t addr) { | |
| 203 | uint64_t val; | |
| 204 | memcpy(&val, (void *)addr, sizeof(val)); | |
| 205 | return val; | |
| 206 | } | |
| 207 | double getDouble(pint_t addr) { | |
| 208 | double val; | |
| 209 | memcpy(&val, (void *)addr, sizeof(val)); | |
| 210 | return val; | |
| 211 | } | |
| 212 | v128 getVector(pint_t addr) { | |
| 213 | v128 val; | |
| 214 | memcpy(&val, (void *)addr, sizeof(val)); | |
| 215 | return val; | |
| 216 | } | |
| 217 | uintptr_t getP(pint_t addr); | |
| 218 | uint64_t getRegister(pint_t addr); | |
| 219 | static uint64_t getULEB128(pint_t &addr, pint_t end); | |
| 220 | static int64_t getSLEB128(pint_t &addr, pint_t end); | |
| 221 | ||
| 222 | pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, | |
| 223 | pint_t datarelBase = 0); | |
| 224 | bool findFunctionName(pint_t addr, char *buf, size_t bufLen, | |
| 225 | unw_word_t *offset); | |
| 226 | bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info); | |
| 227 | bool findOtherFDE(pint_t targetAddr, pint_t &fde); | |
| 228 | ||
| 229 | static LocalAddressSpace sThisAddressSpace; | |
| 230 | }; | |
| 231 | ||
| 232 | inline uintptr_t LocalAddressSpace::getP(pint_t addr) { | |
| 233 | #if __SIZEOF_POINTER__ == 8 | |
| 234 | return get64(addr); | |
| 235 | #else | |
| 236 | return get32(addr); | |
| 237 | #endif | |
| 238 | } | |
| 239 | ||
| 240 | inline uint64_t LocalAddressSpace::getRegister(pint_t addr) { | |
| 241 | #if __SIZEOF_POINTER__ == 8 || defined(__mips64) | |
| 242 | return get64(addr); | |
| 243 | #else | |
| 244 | return get32(addr); | |
| 245 | #endif | |
| 246 | } | |
| 247 | ||
| 248 | /// Read a ULEB128 into a 64-bit word. | |
| 249 | inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) { | |
| 250 | const uint8_t *p = (uint8_t *)addr; | |
| 251 | const uint8_t *pend = (uint8_t *)end; | |
| 252 | uint64_t result = 0; | |
| 253 | int bit = 0; | |
| 254 | do { | |
| 255 | uint64_t b; | |
| 256 | ||
| 257 | if (p == pend) | |
| 258 | _LIBUNWIND_ABORT("truncated uleb128 expression"); | |
| 259 | ||
| 260 | b = *p & 0x7f; | |
| 261 | ||
| 262 | if (bit >= 64 || b << bit >> bit != b) { | |
| 263 | _LIBUNWIND_ABORT("malformed uleb128 expression"); | |
| 264 | } else { | |
| 265 | result |= b << bit; | |
| 266 | bit += 7; | |
| 267 | } | |
| 268 | } while (*p++ >= 0x80); | |
| 269 | addr = (pint_t) p; | |
| 270 | return result; | |
| 271 | } | |
| 272 | ||
| 273 | /// Read a SLEB128 into a 64-bit word. | |
| 274 | inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) { | |
| 275 | const uint8_t *p = (uint8_t *)addr; | |
| 276 | const uint8_t *pend = (uint8_t *)end; | |
| 277 | int64_t result = 0; | |
| 278 | int bit = 0; | |
| 279 | uint8_t byte; | |
| 280 | do { | |
| 281 | if (p == pend) | |
| 282 | _LIBUNWIND_ABORT("truncated sleb128 expression"); | |
| 283 | byte = *p++; | |
| 284 | result |= ((byte & 0x7f) << bit); | |
| 285 | bit += 7; | |
| 286 | } while (byte & 0x80); | |
| 287 | // sign extend negative numbers | |
| 288 | if ((byte & 0x40) != 0) | |
| 289 | result |= (-1ULL) << bit; | |
| 290 | addr = (pint_t) p; | |
| 291 | return result; | |
| 292 | } | |
| 293 | ||
| 294 | inline LocalAddressSpace::pint_t | |
| 295 | LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, | |
| 296 | pint_t datarelBase) { | |
| 297 | pint_t startAddr = addr; | |
| 298 | const uint8_t *p = (uint8_t *)addr; | |
| 299 | pint_t result; | |
| 300 | ||
| 301 | // first get value | |
| 302 | switch (encoding & 0x0F) { | |
| 303 | case DW_EH_PE_ptr: | |
| 304 | result = getP(addr); | |
| 305 | p += sizeof(pint_t); | |
| 306 | addr = (pint_t) p; | |
| 307 | break; | |
| 308 | case DW_EH_PE_uleb128: | |
| 309 | result = (pint_t)getULEB128(addr, end); | |
| 310 | break; | |
| 311 | case DW_EH_PE_udata2: | |
| 312 | result = get16(addr); | |
| 313 | p += 2; | |
| 314 | addr = (pint_t) p; | |
| 315 | break; | |
| 316 | case DW_EH_PE_udata4: | |
| 317 | result = get32(addr); | |
| 318 | p += 4; | |
| 319 | addr = (pint_t) p; | |
| 320 | break; | |
| 321 | case DW_EH_PE_udata8: | |
| 322 | result = (pint_t)get64(addr); | |
| 323 | p += 8; | |
| 324 | addr = (pint_t) p; | |
| 325 | break; | |
| 326 | case DW_EH_PE_sleb128: | |
| 327 | result = (pint_t)getSLEB128(addr, end); | |
| 328 | break; | |
| 329 | case DW_EH_PE_sdata2: | |
| 330 | // Sign extend from signed 16-bit value. | |
| 331 | result = (pint_t)(int16_t)get16(addr); | |
| 332 | p += 2; | |
| 333 | addr = (pint_t) p; | |
| 334 | break; | |
| 335 | case DW_EH_PE_sdata4: | |
| 336 | // Sign extend from signed 32-bit value. | |
| 337 | result = (pint_t)(int32_t)get32(addr); | |
| 338 | p += 4; | |
| 339 | addr = (pint_t) p; | |
| 340 | break; | |
| 341 | case DW_EH_PE_sdata8: | |
| 342 | result = (pint_t)get64(addr); | |
| 343 | p += 8; | |
| 344 | addr = (pint_t) p; | |
| 345 | break; | |
| 346 | default: | |
| 347 | _LIBUNWIND_ABORT("unknown pointer encoding"); | |
| 348 | } | |
| 349 | ||
| 350 | // then add relative offset | |
| 351 | switch (encoding & 0x70) { | |
| 352 | case DW_EH_PE_absptr: | |
| 353 | // do nothing | |
| 354 | break; | |
| 355 | case DW_EH_PE_pcrel: | |
| 356 | result += startAddr; | |
| 357 | break; | |
| 358 | case DW_EH_PE_textrel: | |
| 359 | _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported"); | |
| 360 | break; | |
| 361 | case DW_EH_PE_datarel: | |
| 362 | // DW_EH_PE_datarel is only valid in a few places, so the parameter has a | |
| 363 | // default value of 0, and we abort in the event that someone calls this | |
| 364 | // function with a datarelBase of 0 and DW_EH_PE_datarel encoding. | |
| 365 | if (datarelBase == 0) | |
| 366 | _LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0"); | |
| 367 | result += datarelBase; | |
| 368 | break; | |
| 369 | case DW_EH_PE_funcrel: | |
| 370 | _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported"); | |
| 371 | break; | |
| 372 | case DW_EH_PE_aligned: | |
| 373 | _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported"); | |
| 374 | break; | |
| 375 | default: | |
| 376 | _LIBUNWIND_ABORT("unknown pointer encoding"); | |
| 377 | break; | |
| 378 | } | |
| 379 | ||
| 380 | if (encoding & DW_EH_PE_indirect) | |
| 381 | result = getP(result); | |
| 382 | ||
| 383 | return result; | |
| 384 | } | |
| 385 | ||
| 386 | inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, | |
| 387 | UnwindInfoSections &info) { | |
| 388 | #ifdef __APPLE__ | |
| 389 | dyld_unwind_sections dyldInfo; | |
| 390 | if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) { | |
| 391 | info.dso_base = (uintptr_t)dyldInfo.mh; | |
| 392 | #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) | |
| 393 | info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section; | |
| 394 | info.dwarf_section_length = dyldInfo.dwarf_section_length; | |
| 395 | #endif | |
| 396 | info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section; | |
| 397 | info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length; | |
| 398 | return true; | |
| 399 | } | |
| 400 | #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL) | |
| 401 | // Bare metal is statically linked, so no need to ask the dynamic loader | |
| 402 | info.dwarf_section_length = (uintptr_t)(&__eh_frame_end - &__eh_frame_start); | |
| 403 | info.dwarf_section = (uintptr_t)(&__eh_frame_start); | |
| 404 | _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p", | |
| 405 | (void *)info.dwarf_section, (void *)info.dwarf_section_length); | |
| 406 | #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) | |
| 407 | info.dwarf_index_section = (uintptr_t)(&__eh_frame_hdr_start); | |
| 408 | info.dwarf_index_section_length = (uintptr_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start); | |
| 409 | _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p", | |
| 410 | (void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length); | |
| 411 | #endif | |
| 412 | if (info.dwarf_section_length) | |
| 413 | return true; | |
| 414 | #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL) | |
| 415 | // Bare metal is statically linked, so no need to ask the dynamic loader | |
| 416 | info.arm_section = (uintptr_t)(&__exidx_start); | |
| 417 | info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start); | |
| 418 | _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p", | |
| 419 | (void *)info.arm_section, (void *)info.arm_section_length); | |
| 420 | if (info.arm_section && info.arm_section_length) | |
| 421 | return true; | |
| 422 | #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32) | |
| 423 | HMODULE mods[1024]; | |
| 424 | HANDLE process = GetCurrentProcess(); | |
| 425 | DWORD needed; | |
| 426 | ||
| 427 | if (!EnumProcessModules(process, mods, sizeof(mods), &needed)) | |
| 428 | return false; | |
| 429 | ||
| 430 | for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) { | |
| 431 | PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i]; | |
| 432 | PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew); | |
| 433 | PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader; | |
| 434 | PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh); | |
| 435 | bool found_obj = false; | |
| 436 | bool found_hdr = false; | |
| 437 | ||
| 438 | info.dso_base = (uintptr_t)mods[i]; | |
| 439 | for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) { | |
| 440 | uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i]; | |
| 441 | uintptr_t end = begin + pish->Misc.VirtualSize; | |
| 442 | if (!strncmp((const char *)pish->Name, ".text", | |
| 443 | IMAGE_SIZEOF_SHORT_NAME)) { | |
| 444 | if (targetAddr >= begin && targetAddr < end) | |
| 445 | found_obj = true; | |
| 446 | } else if (!strncmp((const char *)pish->Name, ".eh_frame", | |
| 447 | IMAGE_SIZEOF_SHORT_NAME)) { | |
| 448 | info.dwarf_section = begin; | |
| 449 | info.dwarf_section_length = pish->Misc.VirtualSize; | |
| 450 | found_hdr = true; | |
| 451 | } | |
| 452 | if (found_obj && found_hdr) | |
| 453 | return true; | |
| 454 | } | |
| 455 | } | |
| 456 | return false; | |
| 457 | #elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32) | |
| 458 | // Don't even bother, since Windows has functions that do all this stuff | |
| 459 | // for us. | |
| 460 | return true; | |
| 461 | #elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__) && \ | |
| 462 | (__ANDROID_API__ < 21) | |
| 463 | int length = 0; | |
| 464 | info.arm_section = | |
| 465 | (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length); | |
| 466 | info.arm_section_length = (uintptr_t)length; | |
| 467 | if (info.arm_section && info.arm_section_length) | |
| 468 | return true; | |
| 469 | #elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) | |
| 470 | struct dl_iterate_cb_data { | |
| 471 | LocalAddressSpace *addressSpace; | |
| 472 | UnwindInfoSections *sects; | |
| 473 | uintptr_t targetAddr; | |
| 474 | }; | |
| 475 | ||
| 476 | dl_iterate_cb_data cb_data = {this, &info, targetAddr}; | |
| 477 | int found = dl_iterate_phdr( | |
| 478 | [](struct dl_phdr_info *pinfo, size_t, void *data) -> int { | |
| 479 | auto cbdata = static_cast<dl_iterate_cb_data *>(data); | |
| 480 | bool found_obj = false; | |
| 481 | bool found_hdr = false; | |
| 482 | ||
| 483 | assert(cbdata); | |
| 484 | assert(cbdata->sects); | |
| 485 | ||
| 486 | if (cbdata->targetAddr < pinfo->dlpi_addr) { | |
| 487 | return false; | |
| 488 | } | |
| 489 | ||
| 490 | #if !defined(Elf_Half) | |
| 491 | typedef ElfW(Half) Elf_Half; | |
| 492 | #endif | |
| 493 | #if !defined(Elf_Phdr) | |
| 494 | typedef ElfW(Phdr) Elf_Phdr; | |
| 495 | #endif | |
| 496 | #if !defined(Elf_Addr) && defined(__ANDROID__) | |
| 497 | typedef ElfW(Addr) Elf_Addr; | |
| 498 | #endif | |
| 499 | ||
| 500 | #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) | |
| 501 | #if !defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) | |
| 502 | #error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform." | |
| 503 | #endif | |
| 504 | size_t object_length; | |
| 505 | #if defined(__ANDROID__) | |
| 506 | Elf_Addr image_base = | |
| 507 | pinfo->dlpi_phnum | |
| 508 | ? reinterpret_cast<Elf_Addr>(pinfo->dlpi_phdr) - | |
| 509 | reinterpret_cast<const Elf_Phdr *>(pinfo->dlpi_phdr) | |
| 510 | ->p_offset | |
| 511 | : 0; | |
| 512 | #endif | |
| 513 | ||
| 514 | for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) { | |
| 515 | const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i]; | |
| 516 | if (phdr->p_type == PT_LOAD) { | |
| 517 | uintptr_t begin = pinfo->dlpi_addr + phdr->p_vaddr; | |
| 518 | #if defined(__ANDROID__) | |
| 519 | if (pinfo->dlpi_addr == 0 && phdr->p_vaddr < image_base) | |
| 520 | begin = begin + image_base; | |
| 521 | #endif | |
| 522 | uintptr_t end = begin + phdr->p_memsz; | |
| 523 | if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) { | |
| 524 | cbdata->sects->dso_base = begin; | |
| 525 | object_length = phdr->p_memsz; | |
| 526 | found_obj = true; | |
| 527 | } | |
| 528 | } else if (phdr->p_type == PT_GNU_EH_FRAME) { | |
| 529 | EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo; | |
| 530 | uintptr_t eh_frame_hdr_start = pinfo->dlpi_addr + phdr->p_vaddr; | |
| 531 | #if defined(__ANDROID__) | |
| 532 | if (pinfo->dlpi_addr == 0 && phdr->p_vaddr < image_base) | |
| 533 | eh_frame_hdr_start = eh_frame_hdr_start + image_base; | |
| 534 | #endif | |
| 535 | cbdata->sects->dwarf_index_section = eh_frame_hdr_start; | |
| 536 | cbdata->sects->dwarf_index_section_length = phdr->p_memsz; | |
| 537 | found_hdr = EHHeaderParser<LocalAddressSpace>::decodeEHHdr( | |
| 538 | *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz, | |
| 539 | hdrInfo); | |
| 540 | if (found_hdr) | |
| 541 | cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr; | |
| 542 | } | |
| 543 | } | |
| 544 | ||
| 545 | if (found_obj && found_hdr) { | |
| 546 | cbdata->sects->dwarf_section_length = object_length; | |
| 547 | return true; | |
| 548 | } else { | |
| 549 | return false; | |
| 550 | } | |
| 551 | #else // defined(_LIBUNWIND_ARM_EHABI) | |
| 552 | for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) { | |
| 553 | const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i]; | |
| 554 | if (phdr->p_type == PT_LOAD) { | |
| 555 | uintptr_t begin = pinfo->dlpi_addr + phdr->p_vaddr; | |
| 556 | uintptr_t end = begin + phdr->p_memsz; | |
| 557 | if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) | |
| 558 | found_obj = true; | |
| 559 | } else if (phdr->p_type == PT_ARM_EXIDX) { | |
| 560 | uintptr_t exidx_start = pinfo->dlpi_addr + phdr->p_vaddr; | |
| 561 | cbdata->sects->arm_section = exidx_start; | |
| 562 | cbdata->sects->arm_section_length = phdr->p_memsz; | |
| 563 | found_hdr = true; | |
| 564 | } | |
| 565 | } | |
| 566 | return found_obj && found_hdr; | |
| 567 | #endif | |
| 568 | }, | |
| 569 | &cb_data); | |
| 570 | return static_cast<bool>(found); | |
| 571 | #endif | |
| 572 | ||
| 573 | return false; | |
| 574 | } | |
| 575 | ||
| 576 | ||
| 577 | inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) { | |
| 578 | #ifdef __APPLE__ | |
| 579 | return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde)); | |
| 580 | #else | |
| 581 | // TO DO: if OS has way to dynamically register FDEs, check that. | |
| 582 | (void)targetAddr; | |
| 583 | (void)fde; | |
| 584 | return false; | |
| 585 | #endif | |
| 586 | } | |
| 587 | ||
| 588 | inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf, | |
| 589 | size_t bufLen, | |
| 590 | unw_word_t *offset) { | |
| 591 | #if _LIBUNWIND_USE_DLADDR | |
| 592 | Dl_info dyldInfo; | |
| 593 | if (dladdr((void *)addr, &dyldInfo)) { | |
| 594 | if (dyldInfo.dli_sname != NULL) { | |
| 595 | snprintf(buf, bufLen, "%s", dyldInfo.dli_sname); | |
| 596 | *offset = (addr - (pint_t) dyldInfo.dli_saddr); | |
| 597 | return true; | |
| 598 | } | |
| 599 | } | |
| 600 | #endif | |
| 601 | return false; | |
| 602 | } | |
| 603 | ||
| 604 | ||
| 605 | ||
| 606 | #ifdef UNW_REMOTE | |
| 607 | ||
| 608 | /// RemoteAddressSpace is used as a template parameter to UnwindCursor when | |
| 609 | /// unwinding a thread in the another process. The other process can be a | |
| 610 | /// different endianness and a different pointer size which is handled by | |
| 611 | /// the P template parameter. | |
| 612 | template <typename P> | |
| 613 | class RemoteAddressSpace { | |
| 614 | public: | |
| 615 | RemoteAddressSpace(task_t task) : fTask(task) {} | |
| 616 | ||
| 617 | typedef typename P::uint_t pint_t; | |
| 618 | ||
| 619 | uint8_t get8(pint_t addr); | |
| 620 | uint16_t get16(pint_t addr); | |
| 621 | uint32_t get32(pint_t addr); | |
| 622 | uint64_t get64(pint_t addr); | |
| 623 | pint_t getP(pint_t addr); | |
| 624 | uint64_t getRegister(pint_t addr); | |
| 625 | uint64_t getULEB128(pint_t &addr, pint_t end); | |
| 626 | int64_t getSLEB128(pint_t &addr, pint_t end); | |
| 627 | pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, | |
| 628 | pint_t datarelBase = 0); | |
| 629 | bool findFunctionName(pint_t addr, char *buf, size_t bufLen, | |
| 630 | unw_word_t *offset); | |
| 631 | bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info); | |
| 632 | bool findOtherFDE(pint_t targetAddr, pint_t &fde); | |
| 633 | private: | |
| 634 | void *localCopy(pint_t addr); | |
| 635 | ||
| 636 | task_t fTask; | |
| 637 | }; | |
| 638 | ||
| 639 | template <typename P> uint8_t RemoteAddressSpace<P>::get8(pint_t addr) { | |
| 640 | return *((uint8_t *)localCopy(addr)); | |
| 641 | } | |
| 642 | ||
| 643 | template <typename P> uint16_t RemoteAddressSpace<P>::get16(pint_t addr) { | |
| 644 | return P::E::get16(*(uint16_t *)localCopy(addr)); | |
| 645 | } | |
| 646 | ||
| 647 | template <typename P> uint32_t RemoteAddressSpace<P>::get32(pint_t addr) { | |
| 648 | return P::E::get32(*(uint32_t *)localCopy(addr)); | |
| 649 | } | |
| 650 | ||
| 651 | template <typename P> uint64_t RemoteAddressSpace<P>::get64(pint_t addr) { | |
| 652 | return P::E::get64(*(uint64_t *)localCopy(addr)); | |
| 653 | } | |
| 654 | ||
| 655 | template <typename P> | |
| 656 | typename P::uint_t RemoteAddressSpace<P>::getP(pint_t addr) { | |
| 657 | return P::getP(*(uint64_t *)localCopy(addr)); | |
| 658 | } | |
| 659 | ||
| 660 | template <typename P> | |
| 661 | typename P::uint_t OtherAddressSpace<P>::getRegister(pint_t addr) { | |
| 662 | return P::getRegister(*(uint64_t *)localCopy(addr)); | |
| 663 | } | |
| 664 | ||
| 665 | template <typename P> | |
| 666 | uint64_t OtherAddressSpace<P>::getULEB128(pint_t &addr, pint_t end) { | |
| 667 | uintptr_t size = (end - addr); | |
| 668 | LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr); | |
| 669 | LocalAddressSpace::pint_t sladdr = laddr; | |
| 670 | uint64_t result = LocalAddressSpace::getULEB128(laddr, laddr + size); | |
| 671 | addr += (laddr - sladdr); | |
| 672 | return result; | |
| 673 | } | |
| 674 | ||
| 675 | template <typename P> | |
| 676 | int64_t RemoteAddressSpace<P>::getSLEB128(pint_t &addr, pint_t end) { | |
| 677 | uintptr_t size = (end - addr); | |
| 678 | LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr); | |
| 679 | LocalAddressSpace::pint_t sladdr = laddr; | |
| 680 | uint64_t result = LocalAddressSpace::getSLEB128(laddr, laddr + size); | |
| 681 | addr += (laddr - sladdr); | |
| 682 | return result; | |
| 683 | } | |
| 684 | ||
| 685 | template <typename P> void *RemoteAddressSpace<P>::localCopy(pint_t addr) { | |
| 686 | // FIX ME | |
| 687 | } | |
| 688 | ||
| 689 | template <typename P> | |
| 690 | bool RemoteAddressSpace<P>::findFunctionName(pint_t addr, char *buf, | |
| 691 | size_t bufLen, | |
| 692 | unw_word_t *offset) { | |
| 693 | // FIX ME | |
| 694 | } | |
| 695 | ||
| 696 | /// unw_addr_space is the base class that abstract unw_addr_space_t type in | |
| 697 | /// libunwind.h points to. | |
| 698 | struct unw_addr_space { | |
| 699 | cpu_type_t cpuType; | |
| 700 | task_t taskPort; | |
| 701 | }; | |
| 702 | ||
| 703 | /// unw_addr_space_i386 is the concrete instance that a unw_addr_space_t points | |
| 704 | /// to when examining | |
| 705 | /// a 32-bit intel process. | |
| 706 | struct unw_addr_space_i386 : public unw_addr_space { | |
| 707 | unw_addr_space_i386(task_t task) : oas(task) {} | |
| 708 | RemoteAddressSpace<Pointer32<LittleEndian>> oas; | |
| 709 | }; | |
| 710 | ||
| 711 | /// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t | |
| 712 | /// points to when examining | |
| 713 | /// a 64-bit intel process. | |
| 714 | struct unw_addr_space_x86_64 : public unw_addr_space { | |
| 715 | unw_addr_space_x86_64(task_t task) : oas(task) {} | |
| 716 | RemoteAddressSpace<Pointer64<LittleEndian>> oas; | |
| 717 | }; | |
| 718 | ||
| 719 | /// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points | |
| 720 | /// to when examining | |
| 721 | /// a 32-bit PowerPC process. | |
| 722 | struct unw_addr_space_ppc : public unw_addr_space { | |
| 723 | unw_addr_space_ppc(task_t task) : oas(task) {} | |
| 724 | RemoteAddressSpace<Pointer32<BigEndian>> oas; | |
| 725 | }; | |
| 726 | ||
| 727 | /// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points | |
| 728 | /// to when examining a 64-bit PowerPC process. | |
| 729 | struct unw_addr_space_ppc64 : public unw_addr_space { | |
| 730 | unw_addr_space_ppc64(task_t task) : oas(task) {} | |
| 731 | RemoteAddressSpace<Pointer64<LittleEndian>> oas; | |
| 732 | }; | |
| 733 | ||
| 734 | #endif // UNW_REMOTE | |
| 735 | ||
| 736 | } // namespace libunwind | |
| 737 | ||
| 738 | #endif // __ADDRESSSPACE_HPP__ |
libunwind/src/CompactUnwinder.hpp created+698| ... | ... | @@ -0,0 +1,698 @@ |
| 1 | //===-------------------------- CompactUnwinder.hpp -----------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is dual licensed under the MIT and the University of Illinois Open | |
| 6 | // Source Licenses. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | // | |
| 9 | // Does runtime stack unwinding using compact unwind encodings. | |
| 10 | // | |
| 11 | //===----------------------------------------------------------------------===// | |
| 12 | ||
| 13 | #ifndef __COMPACT_UNWINDER_HPP__ | |
| 14 | #define __COMPACT_UNWINDER_HPP__ | |
| 15 | ||
| 16 | #include <stdint.h> | |
| 17 | #include <stdlib.h> | |
| 18 | ||
| 19 | #include <libunwind.h> | |
| 20 | #include <mach-o/compact_unwind_encoding.h> | |
| 21 | ||
| 22 | #include "Registers.hpp" | |
| 23 | ||
| 24 | #define EXTRACT_BITS(value, mask) \ | |
| 25 | ((value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask))) - 1)) | |
| 26 | ||
| 27 | namespace libunwind { | |
| 28 | ||
| 29 | #if defined(_LIBUNWIND_TARGET_I386) | |
| 30 | /// CompactUnwinder_x86 uses a compact unwind info to virtually "step" (aka | |
| 31 | /// unwind) by modifying a Registers_x86 register set | |
| 32 | template <typename A> | |
| 33 | class CompactUnwinder_x86 { | |
| 34 | public: | |
| 35 | ||
| 36 | static int stepWithCompactEncoding(compact_unwind_encoding_t info, | |
| 37 | uint32_t functionStart, A &addressSpace, | |
| 38 | Registers_x86 &registers); | |
| 39 | ||
| 40 | private: | |
| 41 | typename A::pint_t pint_t; | |
| 42 | ||
| 43 | static void frameUnwind(A &addressSpace, Registers_x86 &registers); | |
| 44 | static void framelessUnwind(A &addressSpace, | |
| 45 | typename A::pint_t returnAddressLocation, | |
| 46 | Registers_x86 &registers); | |
| 47 | static int | |
| 48 | stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding, | |
| 49 | uint32_t functionStart, A &addressSpace, | |
| 50 | Registers_x86 &registers); | |
| 51 | static int stepWithCompactEncodingFrameless( | |
| 52 | compact_unwind_encoding_t compactEncoding, uint32_t functionStart, | |
| 53 | A &addressSpace, Registers_x86 &registers, bool indirectStackSize); | |
| 54 | }; | |
| 55 | ||
| 56 | template <typename A> | |
| 57 | int CompactUnwinder_x86<A>::stepWithCompactEncoding( | |
| 58 | compact_unwind_encoding_t compactEncoding, uint32_t functionStart, | |
| 59 | A &addressSpace, Registers_x86 &registers) { | |
| 60 | switch (compactEncoding & UNWIND_X86_MODE_MASK) { | |
| 61 | case UNWIND_X86_MODE_EBP_FRAME: | |
| 62 | return stepWithCompactEncodingEBPFrame(compactEncoding, functionStart, | |
| 63 | addressSpace, registers); | |
| 64 | case UNWIND_X86_MODE_STACK_IMMD: | |
| 65 | return stepWithCompactEncodingFrameless(compactEncoding, functionStart, | |
| 66 | addressSpace, registers, false); | |
| 67 | case UNWIND_X86_MODE_STACK_IND: | |
| 68 | return stepWithCompactEncodingFrameless(compactEncoding, functionStart, | |
| 69 | addressSpace, registers, true); | |
| 70 | } | |
| 71 | _LIBUNWIND_ABORT("invalid compact unwind encoding"); | |
| 72 | } | |
| 73 | ||
| 74 | template <typename A> | |
| 75 | int CompactUnwinder_x86<A>::stepWithCompactEncodingEBPFrame( | |
| 76 | compact_unwind_encoding_t compactEncoding, uint32_t functionStart, | |
| 77 | A &addressSpace, Registers_x86 &registers) { | |
| 78 | uint32_t savedRegistersOffset = | |
| 79 | EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_OFFSET); | |
| 80 | uint32_t savedRegistersLocations = | |
| 81 | EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_REGISTERS); | |
| 82 | ||
| 83 | uint32_t savedRegisters = registers.getEBP() - 4 * savedRegistersOffset; | |
| 84 | for (int i = 0; i < 5; ++i) { | |
| 85 | switch (savedRegistersLocations & 0x7) { | |
| 86 | case UNWIND_X86_REG_NONE: | |
| 87 | // no register saved in this slot | |
| 88 | break; | |
| 89 | case UNWIND_X86_REG_EBX: | |
| 90 | registers.setEBX(addressSpace.get32(savedRegisters)); | |
| 91 | break; | |
| 92 | case UNWIND_X86_REG_ECX: | |
| 93 | registers.setECX(addressSpace.get32(savedRegisters)); | |
| 94 | break; | |
| 95 | case UNWIND_X86_REG_EDX: | |
| 96 | registers.setEDX(addressSpace.get32(savedRegisters)); | |
| 97 | break; | |
| 98 | case UNWIND_X86_REG_EDI: | |
| 99 | registers.setEDI(addressSpace.get32(savedRegisters)); | |
| 100 | break; | |
| 101 | case UNWIND_X86_REG_ESI: | |
| 102 | registers.setESI(addressSpace.get32(savedRegisters)); | |
| 103 | break; | |
| 104 | default: | |
| 105 | (void)functionStart; | |
| 106 | _LIBUNWIND_DEBUG_LOG("bad register for EBP frame, encoding=%08X for " | |
| 107 | "function starting at 0x%X", | |
| 108 | compactEncoding, functionStart); | |
| 109 | _LIBUNWIND_ABORT("invalid compact unwind encoding"); | |
| 110 | } | |
| 111 | savedRegisters += 4; | |
| 112 | savedRegistersLocations = (savedRegistersLocations >> 3); | |
| 113 | } | |
| 114 | frameUnwind(addressSpace, registers); | |
| 115 | return UNW_STEP_SUCCESS; | |
| 116 | } | |
| 117 | ||
| 118 | template <typename A> | |
| 119 | int CompactUnwinder_x86<A>::stepWithCompactEncodingFrameless( | |
| 120 | compact_unwind_encoding_t encoding, uint32_t functionStart, | |
| 121 | A &addressSpace, Registers_x86 &registers, bool indirectStackSize) { | |
| 122 | uint32_t stackSizeEncoded = | |
| 123 | EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_SIZE); | |
| 124 | uint32_t stackAdjust = | |
| 125 | EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST); | |
| 126 | uint32_t regCount = | |
| 127 | EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT); | |
| 128 | uint32_t permutation = | |
| 129 | EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION); | |
| 130 | uint32_t stackSize = stackSizeEncoded * 4; | |
| 131 | if (indirectStackSize) { | |
| 132 | // stack size is encoded in subl $xxx,%esp instruction | |
| 133 | uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded); | |
| 134 | stackSize = subl + 4 * stackAdjust; | |
| 135 | } | |
| 136 | // decompress permutation | |
| 137 | uint32_t permunreg[6]; | |
| 138 | switch (regCount) { | |
| 139 | case 6: | |
| 140 | permunreg[0] = permutation / 120; | |
| 141 | permutation -= (permunreg[0] * 120); | |
| 142 | permunreg[1] = permutation / 24; | |
| 143 | permutation -= (permunreg[1] * 24); | |
| 144 | permunreg[2] = permutation / 6; | |
| 145 | permutation -= (permunreg[2] * 6); | |
| 146 | permunreg[3] = permutation / 2; | |
| 147 | permutation -= (permunreg[3] * 2); | |
| 148 | permunreg[4] = permutation; | |
| 149 | permunreg[5] = 0; | |
| 150 | break; | |
| 151 | case 5: | |
| 152 | permunreg[0] = permutation / 120; | |
| 153 | permutation -= (permunreg[0] * 120); | |
| 154 | permunreg[1] = permutation / 24; | |
| 155 | permutation -= (permunreg[1] * 24); | |
| 156 | permunreg[2] = permutation / 6; | |
| 157 | permutation -= (permunreg[2] * 6); | |
| 158 | permunreg[3] = permutation / 2; | |
| 159 | permutation -= (permunreg[3] * 2); | |
| 160 | permunreg[4] = permutation; | |
| 161 | break; | |
| 162 | case 4: | |
| 163 | permunreg[0] = permutation / 60; | |
| 164 | permutation -= (permunreg[0] * 60); | |
| 165 | permunreg[1] = permutation / 12; | |
| 166 | permutation -= (permunreg[1] * 12); | |
| 167 | permunreg[2] = permutation / 3; | |
| 168 | permutation -= (permunreg[2] * 3); | |
| 169 | permunreg[3] = permutation; | |
| 170 | break; | |
| 171 | case 3: | |
| 172 | permunreg[0] = permutation / 20; | |
| 173 | permutation -= (permunreg[0] * 20); | |
| 174 | permunreg[1] = permutation / 4; | |
| 175 | permutation -= (permunreg[1] * 4); | |
| 176 | permunreg[2] = permutation; | |
| 177 | break; | |
| 178 | case 2: | |
| 179 | permunreg[0] = permutation / 5; | |
| 180 | permutation -= (permunreg[0] * 5); | |
| 181 | permunreg[1] = permutation; | |
| 182 | break; | |
| 183 | case 1: | |
| 184 | permunreg[0] = permutation; | |
| 185 | break; | |
| 186 | } | |
| 187 | // re-number registers back to standard numbers | |
| 188 | int registersSaved[6]; | |
| 189 | bool used[7] = { false, false, false, false, false, false, false }; | |
| 190 | for (uint32_t i = 0; i < regCount; ++i) { | |
| 191 | uint32_t renum = 0; | |
| 192 | for (int u = 1; u < 7; ++u) { | |
| 193 | if (!used[u]) { | |
| 194 | if (renum == permunreg[i]) { | |
| 195 | registersSaved[i] = u; | |
| 196 | used[u] = true; | |
| 197 | break; | |
| 198 | } | |
| 199 | ++renum; | |
| 200 | } | |
| 201 | } | |
| 202 | } | |
| 203 | uint32_t savedRegisters = registers.getSP() + stackSize - 4 - 4 * regCount; | |
| 204 | for (uint32_t i = 0; i < regCount; ++i) { | |
| 205 | switch (registersSaved[i]) { | |
| 206 | case UNWIND_X86_REG_EBX: | |
| 207 | registers.setEBX(addressSpace.get32(savedRegisters)); | |
| 208 | break; | |
| 209 | case UNWIND_X86_REG_ECX: | |
| 210 | registers.setECX(addressSpace.get32(savedRegisters)); | |
| 211 | break; | |
| 212 | case UNWIND_X86_REG_EDX: | |
| 213 | registers.setEDX(addressSpace.get32(savedRegisters)); | |
| 214 | break; | |
| 215 | case UNWIND_X86_REG_EDI: | |
| 216 | registers.setEDI(addressSpace.get32(savedRegisters)); | |
| 217 | break; | |
| 218 | case UNWIND_X86_REG_ESI: | |
| 219 | registers.setESI(addressSpace.get32(savedRegisters)); | |
| 220 | break; | |
| 221 | case UNWIND_X86_REG_EBP: | |
| 222 | registers.setEBP(addressSpace.get32(savedRegisters)); | |
| 223 | break; | |
| 224 | default: | |
| 225 | _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for " | |
| 226 | "function starting at 0x%X", | |
| 227 | encoding, functionStart); | |
| 228 | _LIBUNWIND_ABORT("invalid compact unwind encoding"); | |
| 229 | } | |
| 230 | savedRegisters += 4; | |
| 231 | } | |
| 232 | framelessUnwind(addressSpace, savedRegisters, registers); | |
| 233 | return UNW_STEP_SUCCESS; | |
| 234 | } | |
| 235 | ||
| 236 | ||
| 237 | template <typename A> | |
| 238 | void CompactUnwinder_x86<A>::frameUnwind(A &addressSpace, | |
| 239 | Registers_x86 &registers) { | |
| 240 | typename A::pint_t bp = registers.getEBP(); | |
| 241 | // ebp points to old ebp | |
| 242 | registers.setEBP(addressSpace.get32(bp)); | |
| 243 | // old esp is ebp less saved ebp and return address | |
| 244 | registers.setSP((uint32_t)bp + 8); | |
| 245 | // pop return address into eip | |
| 246 | registers.setIP(addressSpace.get32(bp + 4)); | |
| 247 | } | |
| 248 | ||
| 249 | template <typename A> | |
| 250 | void CompactUnwinder_x86<A>::framelessUnwind( | |
| 251 | A &addressSpace, typename A::pint_t returnAddressLocation, | |
| 252 | Registers_x86 &registers) { | |
| 253 | // return address is on stack after last saved register | |
| 254 | registers.setIP(addressSpace.get32(returnAddressLocation)); | |
| 255 | // old esp is before return address | |
| 256 | registers.setSP((uint32_t)returnAddressLocation + 4); | |
| 257 | } | |
| 258 | #endif // _LIBUNWIND_TARGET_I386 | |
| 259 | ||
| 260 | ||
| 261 | #if defined(_LIBUNWIND_TARGET_X86_64) | |
| 262 | /// CompactUnwinder_x86_64 uses a compact unwind info to virtually "step" (aka | |
| 263 | /// unwind) by modifying a Registers_x86_64 register set | |
| 264 | template <typename A> | |
| 265 | class CompactUnwinder_x86_64 { | |
| 266 | public: | |
| 267 | ||
| 268 | static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding, | |
| 269 | uint64_t functionStart, A &addressSpace, | |
| 270 | Registers_x86_64 &registers); | |
| 271 | ||
| 272 | private: | |
| 273 | typename A::pint_t pint_t; | |
| 274 | ||
| 275 | static void frameUnwind(A &addressSpace, Registers_x86_64 &registers); | |
| 276 | static void framelessUnwind(A &addressSpace, uint64_t returnAddressLocation, | |
| 277 | Registers_x86_64 &registers); | |
| 278 | static int | |
| 279 | stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding, | |
| 280 | uint64_t functionStart, A &addressSpace, | |
| 281 | Registers_x86_64 &registers); | |
| 282 | static int stepWithCompactEncodingFrameless( | |
| 283 | compact_unwind_encoding_t compactEncoding, uint64_t functionStart, | |
| 284 | A &addressSpace, Registers_x86_64 &registers, bool indirectStackSize); | |
| 285 | }; | |
| 286 | ||
| 287 | template <typename A> | |
| 288 | int CompactUnwinder_x86_64<A>::stepWithCompactEncoding( | |
| 289 | compact_unwind_encoding_t compactEncoding, uint64_t functionStart, | |
| 290 | A &addressSpace, Registers_x86_64 &registers) { | |
| 291 | switch (compactEncoding & UNWIND_X86_64_MODE_MASK) { | |
| 292 | case UNWIND_X86_64_MODE_RBP_FRAME: | |
| 293 | return stepWithCompactEncodingRBPFrame(compactEncoding, functionStart, | |
| 294 | addressSpace, registers); | |
| 295 | case UNWIND_X86_64_MODE_STACK_IMMD: | |
| 296 | return stepWithCompactEncodingFrameless(compactEncoding, functionStart, | |
| 297 | addressSpace, registers, false); | |
| 298 | case UNWIND_X86_64_MODE_STACK_IND: | |
| 299 | return stepWithCompactEncodingFrameless(compactEncoding, functionStart, | |
| 300 | addressSpace, registers, true); | |
| 301 | } | |
| 302 | _LIBUNWIND_ABORT("invalid compact unwind encoding"); | |
| 303 | } | |
| 304 | ||
| 305 | template <typename A> | |
| 306 | int CompactUnwinder_x86_64<A>::stepWithCompactEncodingRBPFrame( | |
| 307 | compact_unwind_encoding_t compactEncoding, uint64_t functionStart, | |
| 308 | A &addressSpace, Registers_x86_64 &registers) { | |
| 309 | uint32_t savedRegistersOffset = | |
| 310 | EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_OFFSET); | |
| 311 | uint32_t savedRegistersLocations = | |
| 312 | EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_REGISTERS); | |
| 313 | ||
| 314 | uint64_t savedRegisters = registers.getRBP() - 8 * savedRegistersOffset; | |
| 315 | for (int i = 0; i < 5; ++i) { | |
| 316 | switch (savedRegistersLocations & 0x7) { | |
| 317 | case UNWIND_X86_64_REG_NONE: | |
| 318 | // no register saved in this slot | |
| 319 | break; | |
| 320 | case UNWIND_X86_64_REG_RBX: | |
| 321 | registers.setRBX(addressSpace.get64(savedRegisters)); | |
| 322 | break; | |
| 323 | case UNWIND_X86_64_REG_R12: | |
| 324 | registers.setR12(addressSpace.get64(savedRegisters)); | |
| 325 | break; | |
| 326 | case UNWIND_X86_64_REG_R13: | |
| 327 | registers.setR13(addressSpace.get64(savedRegisters)); | |
| 328 | break; | |
| 329 | case UNWIND_X86_64_REG_R14: | |
| 330 | registers.setR14(addressSpace.get64(savedRegisters)); | |
| 331 | break; | |
| 332 | case UNWIND_X86_64_REG_R15: | |
| 333 | registers.setR15(addressSpace.get64(savedRegisters)); | |
| 334 | break; | |
| 335 | default: | |
| 336 | (void)functionStart; | |
| 337 | _LIBUNWIND_DEBUG_LOG("bad register for RBP frame, encoding=%08X for " | |
| 338 | "function starting at 0x%llX", | |
| 339 | compactEncoding, functionStart); | |
| 340 | _LIBUNWIND_ABORT("invalid compact unwind encoding"); | |
| 341 | } | |
| 342 | savedRegisters += 8; | |
| 343 | savedRegistersLocations = (savedRegistersLocations >> 3); | |
| 344 | } | |
| 345 | frameUnwind(addressSpace, registers); | |
| 346 | return UNW_STEP_SUCCESS; | |
| 347 | } | |
| 348 | ||
| 349 | template <typename A> | |
| 350 | int CompactUnwinder_x86_64<A>::stepWithCompactEncodingFrameless( | |
| 351 | compact_unwind_encoding_t encoding, uint64_t functionStart, A &addressSpace, | |
| 352 | Registers_x86_64 &registers, bool indirectStackSize) { | |
| 353 | uint32_t stackSizeEncoded = | |
| 354 | EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE); | |
| 355 | uint32_t stackAdjust = | |
| 356 | EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST); | |
| 357 | uint32_t regCount = | |
| 358 | EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT); | |
| 359 | uint32_t permutation = | |
| 360 | EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION); | |
| 361 | uint32_t stackSize = stackSizeEncoded * 8; | |
| 362 | if (indirectStackSize) { | |
| 363 | // stack size is encoded in subl $xxx,%esp instruction | |
| 364 | uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded); | |
| 365 | stackSize = subl + 8 * stackAdjust; | |
| 366 | } | |
| 367 | // decompress permutation | |
| 368 | uint32_t permunreg[6]; | |
| 369 | switch (regCount) { | |
| 370 | case 6: | |
| 371 | permunreg[0] = permutation / 120; | |
| 372 | permutation -= (permunreg[0] * 120); | |
| 373 | permunreg[1] = permutation / 24; | |
| 374 | permutation -= (permunreg[1] * 24); | |
| 375 | permunreg[2] = permutation / 6; | |
| 376 | permutation -= (permunreg[2] * 6); | |
| 377 | permunreg[3] = permutation / 2; | |
| 378 | permutation -= (permunreg[3] * 2); | |
| 379 | permunreg[4] = permutation; | |
| 380 | permunreg[5] = 0; | |
| 381 | break; | |
| 382 | case 5: | |
| 383 | permunreg[0] = permutation / 120; | |
| 384 | permutation -= (permunreg[0] * 120); | |
| 385 | permunreg[1] = permutation / 24; | |
| 386 | permutation -= (permunreg[1] * 24); | |
| 387 | permunreg[2] = permutation / 6; | |
| 388 | permutation -= (permunreg[2] * 6); | |
| 389 | permunreg[3] = permutation / 2; | |
| 390 | permutation -= (permunreg[3] * 2); | |
| 391 | permunreg[4] = permutation; | |
| 392 | break; | |
| 393 | case 4: | |
| 394 | permunreg[0] = permutation / 60; | |
| 395 | permutation -= (permunreg[0] * 60); | |
| 396 | permunreg[1] = permutation / 12; | |
| 397 | permutation -= (permunreg[1] * 12); | |
| 398 | permunreg[2] = permutation / 3; | |
| 399 | permutation -= (permunreg[2] * 3); | |
| 400 | permunreg[3] = permutation; | |
| 401 | break; | |
| 402 | case 3: | |
| 403 | permunreg[0] = permutation / 20; | |
| 404 | permutation -= (permunreg[0] * 20); | |
| 405 | permunreg[1] = permutation / 4; | |
| 406 | permutation -= (permunreg[1] * 4); | |
| 407 | permunreg[2] = permutation; | |
| 408 | break; | |
| 409 | case 2: | |
| 410 | permunreg[0] = permutation / 5; | |
| 411 | permutation -= (permunreg[0] * 5); | |
| 412 | permunreg[1] = permutation; | |
| 413 | break; | |
| 414 | case 1: | |
| 415 | permunreg[0] = permutation; | |
| 416 | break; | |
| 417 | } | |
| 418 | // re-number registers back to standard numbers | |
| 419 | int registersSaved[6]; | |
| 420 | bool used[7] = { false, false, false, false, false, false, false }; | |
| 421 | for (uint32_t i = 0; i < regCount; ++i) { | |
| 422 | uint32_t renum = 0; | |
| 423 | for (int u = 1; u < 7; ++u) { | |
| 424 | if (!used[u]) { | |
| 425 | if (renum == permunreg[i]) { | |
| 426 | registersSaved[i] = u; | |
| 427 | used[u] = true; | |
| 428 | break; | |
| 429 | } | |
| 430 | ++renum; | |
| 431 | } | |
| 432 | } | |
| 433 | } | |
| 434 | uint64_t savedRegisters = registers.getSP() + stackSize - 8 - 8 * regCount; | |
| 435 | for (uint32_t i = 0; i < regCount; ++i) { | |
| 436 | switch (registersSaved[i]) { | |
| 437 | case UNWIND_X86_64_REG_RBX: | |
| 438 | registers.setRBX(addressSpace.get64(savedRegisters)); | |
| 439 | break; | |
| 440 | case UNWIND_X86_64_REG_R12: | |
| 441 | registers.setR12(addressSpace.get64(savedRegisters)); | |
| 442 | break; | |
| 443 | case UNWIND_X86_64_REG_R13: | |
| 444 | registers.setR13(addressSpace.get64(savedRegisters)); | |
| 445 | break; | |
| 446 | case UNWIND_X86_64_REG_R14: | |
| 447 | registers.setR14(addressSpace.get64(savedRegisters)); | |
| 448 | break; | |
| 449 | case UNWIND_X86_64_REG_R15: | |
| 450 | registers.setR15(addressSpace.get64(savedRegisters)); | |
| 451 | break; | |
| 452 | case UNWIND_X86_64_REG_RBP: | |
| 453 | registers.setRBP(addressSpace.get64(savedRegisters)); | |
| 454 | break; | |
| 455 | default: | |
| 456 | _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for " | |
| 457 | "function starting at 0x%llX", | |
| 458 | encoding, functionStart); | |
| 459 | _LIBUNWIND_ABORT("invalid compact unwind encoding"); | |
| 460 | } | |
| 461 | savedRegisters += 8; | |
| 462 | } | |
| 463 | framelessUnwind(addressSpace, savedRegisters, registers); | |
| 464 | return UNW_STEP_SUCCESS; | |
| 465 | } | |
| 466 | ||
| 467 | ||
| 468 | template <typename A> | |
| 469 | void CompactUnwinder_x86_64<A>::frameUnwind(A &addressSpace, | |
| 470 | Registers_x86_64 &registers) { | |
| 471 | uint64_t rbp = registers.getRBP(); | |
| 472 | // ebp points to old ebp | |
| 473 | registers.setRBP(addressSpace.get64(rbp)); | |
| 474 | // old esp is ebp less saved ebp and return address | |
| 475 | registers.setSP(rbp + 16); | |
| 476 | // pop return address into eip | |
| 477 | registers.setIP(addressSpace.get64(rbp + 8)); | |
| 478 | } | |
| 479 | ||
| 480 | template <typename A> | |
| 481 | void CompactUnwinder_x86_64<A>::framelessUnwind(A &addressSpace, | |
| 482 | uint64_t returnAddressLocation, | |
| 483 | Registers_x86_64 &registers) { | |
| 484 | // return address is on stack after last saved register | |
| 485 | registers.setIP(addressSpace.get64(returnAddressLocation)); | |
| 486 | // old esp is before return address | |
| 487 | registers.setSP(returnAddressLocation + 8); | |
| 488 | } | |
| 489 | #endif // _LIBUNWIND_TARGET_X86_64 | |
| 490 | ||
| 491 | ||
| 492 | ||
| 493 | #if defined(_LIBUNWIND_TARGET_AARCH64) | |
| 494 | /// CompactUnwinder_arm64 uses a compact unwind info to virtually "step" (aka | |
| 495 | /// unwind) by modifying a Registers_arm64 register set | |
| 496 | template <typename A> | |
| 497 | class CompactUnwinder_arm64 { | |
| 498 | public: | |
| 499 | ||
| 500 | static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding, | |
| 501 | uint64_t functionStart, A &addressSpace, | |
| 502 | Registers_arm64 &registers); | |
| 503 | ||
| 504 | private: | |
| 505 | typename A::pint_t pint_t; | |
| 506 | ||
| 507 | static int | |
| 508 | stepWithCompactEncodingFrame(compact_unwind_encoding_t compactEncoding, | |
| 509 | uint64_t functionStart, A &addressSpace, | |
| 510 | Registers_arm64 &registers); | |
| 511 | static int stepWithCompactEncodingFrameless( | |
| 512 | compact_unwind_encoding_t compactEncoding, uint64_t functionStart, | |
| 513 | A &addressSpace, Registers_arm64 &registers); | |
| 514 | }; | |
| 515 | ||
| 516 | template <typename A> | |
| 517 | int CompactUnwinder_arm64<A>::stepWithCompactEncoding( | |
| 518 | compact_unwind_encoding_t compactEncoding, uint64_t functionStart, | |
| 519 | A &addressSpace, Registers_arm64 &registers) { | |
| 520 | switch (compactEncoding & UNWIND_ARM64_MODE_MASK) { | |
| 521 | case UNWIND_ARM64_MODE_FRAME: | |
| 522 | return stepWithCompactEncodingFrame(compactEncoding, functionStart, | |
| 523 | addressSpace, registers); | |
| 524 | case UNWIND_ARM64_MODE_FRAMELESS: | |
| 525 | return stepWithCompactEncodingFrameless(compactEncoding, functionStart, | |
| 526 | addressSpace, registers); | |
| 527 | } | |
| 528 | _LIBUNWIND_ABORT("invalid compact unwind encoding"); | |
| 529 | } | |
| 530 | ||
| 531 | template <typename A> | |
| 532 | int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrameless( | |
| 533 | compact_unwind_encoding_t encoding, uint64_t, A &addressSpace, | |
| 534 | Registers_arm64 &registers) { | |
| 535 | uint32_t stackSize = | |
| 536 | 16 * EXTRACT_BITS(encoding, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK); | |
| 537 | ||
| 538 | uint64_t savedRegisterLoc = registers.getSP() + stackSize; | |
| 539 | ||
| 540 | if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) { | |
| 541 | registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc)); | |
| 542 | savedRegisterLoc -= 8; | |
| 543 | registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc)); | |
| 544 | savedRegisterLoc -= 8; | |
| 545 | } | |
| 546 | if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) { | |
| 547 | registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc)); | |
| 548 | savedRegisterLoc -= 8; | |
| 549 | registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc)); | |
| 550 | savedRegisterLoc -= 8; | |
| 551 | } | |
| 552 | if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) { | |
| 553 | registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc)); | |
| 554 | savedRegisterLoc -= 8; | |
| 555 | registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc)); | |
| 556 | savedRegisterLoc -= 8; | |
| 557 | } | |
| 558 | if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) { | |
| 559 | registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc)); | |
| 560 | savedRegisterLoc -= 8; | |
| 561 | registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc)); | |
| 562 | savedRegisterLoc -= 8; | |
| 563 | } | |
| 564 | if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) { | |
| 565 | registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc)); | |
| 566 | savedRegisterLoc -= 8; | |
| 567 | registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc)); | |
| 568 | savedRegisterLoc -= 8; | |
| 569 | } | |
| 570 | ||
| 571 | if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) { | |
| 572 | registers.setFloatRegister(UNW_ARM64_D8, | |
| 573 | addressSpace.getDouble(savedRegisterLoc)); | |
| 574 | savedRegisterLoc -= 8; | |
| 575 | registers.setFloatRegister(UNW_ARM64_D9, | |
| 576 | addressSpace.getDouble(savedRegisterLoc)); | |
| 577 | savedRegisterLoc -= 8; | |
| 578 | } | |
| 579 | if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) { | |
| 580 | registers.setFloatRegister(UNW_ARM64_D10, | |
| 581 | addressSpace.getDouble(savedRegisterLoc)); | |
| 582 | savedRegisterLoc -= 8; | |
| 583 | registers.setFloatRegister(UNW_ARM64_D11, | |
| 584 | addressSpace.getDouble(savedRegisterLoc)); | |
| 585 | savedRegisterLoc -= 8; | |
| 586 | } | |
| 587 | if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) { | |
| 588 | registers.setFloatRegister(UNW_ARM64_D12, | |
| 589 | addressSpace.getDouble(savedRegisterLoc)); | |
| 590 | savedRegisterLoc -= 8; | |
| 591 | registers.setFloatRegister(UNW_ARM64_D13, | |
| 592 | addressSpace.getDouble(savedRegisterLoc)); | |
| 593 | savedRegisterLoc -= 8; | |
| 594 | } | |
| 595 | if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) { | |
| 596 | registers.setFloatRegister(UNW_ARM64_D14, | |
| 597 | addressSpace.getDouble(savedRegisterLoc)); | |
| 598 | savedRegisterLoc -= 8; | |
| 599 | registers.setFloatRegister(UNW_ARM64_D15, | |
| 600 | addressSpace.getDouble(savedRegisterLoc)); | |
| 601 | savedRegisterLoc -= 8; | |
| 602 | } | |
| 603 | ||
| 604 | // subtract stack size off of sp | |
| 605 | registers.setSP(savedRegisterLoc); | |
| 606 | ||
| 607 | // set pc to be value in lr | |
| 608 | registers.setIP(registers.getRegister(UNW_ARM64_LR)); | |
| 609 | ||
| 610 | return UNW_STEP_SUCCESS; | |
| 611 | } | |
| 612 | ||
| 613 | template <typename A> | |
| 614 | int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrame( | |
| 615 | compact_unwind_encoding_t encoding, uint64_t, A &addressSpace, | |
| 616 | Registers_arm64 &registers) { | |
| 617 | uint64_t savedRegisterLoc = registers.getFP() - 8; | |
| 618 | ||
| 619 | if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) { | |
| 620 | registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc)); | |
| 621 | savedRegisterLoc -= 8; | |
| 622 | registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc)); | |
| 623 | savedRegisterLoc -= 8; | |
| 624 | } | |
| 625 | if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) { | |
| 626 | registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc)); | |
| 627 | savedRegisterLoc -= 8; | |
| 628 | registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc)); | |
| 629 | savedRegisterLoc -= 8; | |
| 630 | } | |
| 631 | if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) { | |
| 632 | registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc)); | |
| 633 | savedRegisterLoc -= 8; | |
| 634 | registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc)); | |
| 635 | savedRegisterLoc -= 8; | |
| 636 | } | |
| 637 | if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) { | |
| 638 | registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc)); | |
| 639 | savedRegisterLoc -= 8; | |
| 640 | registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc)); | |
| 641 | savedRegisterLoc -= 8; | |
| 642 | } | |
| 643 | if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) { | |
| 644 | registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc)); | |
| 645 | savedRegisterLoc -= 8; | |
| 646 | registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc)); | |
| 647 | savedRegisterLoc -= 8; | |
| 648 | } | |
| 649 | ||
| 650 | if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) { | |
| 651 | registers.setFloatRegister(UNW_ARM64_D8, | |
| 652 | addressSpace.getDouble(savedRegisterLoc)); | |
| 653 | savedRegisterLoc -= 8; | |
| 654 | registers.setFloatRegister(UNW_ARM64_D9, | |
| 655 | addressSpace.getDouble(savedRegisterLoc)); | |
| 656 | savedRegisterLoc -= 8; | |
| 657 | } | |
| 658 | if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) { | |
| 659 | registers.setFloatRegister(UNW_ARM64_D10, | |
| 660 | addressSpace.getDouble(savedRegisterLoc)); | |
| 661 | savedRegisterLoc -= 8; | |
| 662 | registers.setFloatRegister(UNW_ARM64_D11, | |
| 663 | addressSpace.getDouble(savedRegisterLoc)); | |
| 664 | savedRegisterLoc -= 8; | |
| 665 | } | |
| 666 | if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) { | |
| 667 | registers.setFloatRegister(UNW_ARM64_D12, | |
| 668 | addressSpace.getDouble(savedRegisterLoc)); | |
| 669 | savedRegisterLoc -= 8; | |
| 670 | registers.setFloatRegister(UNW_ARM64_D13, | |
| 671 | addressSpace.getDouble(savedRegisterLoc)); | |
| 672 | savedRegisterLoc -= 8; | |
| 673 | } | |
| 674 | if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) { | |
| 675 | registers.setFloatRegister(UNW_ARM64_D14, | |
| 676 | addressSpace.getDouble(savedRegisterLoc)); | |
| 677 | savedRegisterLoc -= 8; | |
| 678 | registers.setFloatRegister(UNW_ARM64_D15, | |
| 679 | addressSpace.getDouble(savedRegisterLoc)); | |
| 680 | savedRegisterLoc -= 8; | |
| 681 | } | |
| 682 | ||
| 683 | uint64_t fp = registers.getFP(); | |
| 684 | // fp points to old fp | |
| 685 | registers.setFP(addressSpace.get64(fp)); | |
| 686 | // old sp is fp less saved fp and lr | |
| 687 | registers.setSP(fp + 16); | |
| 688 | // pop return address into pc | |
| 689 | registers.setIP(addressSpace.get64(fp + 8)); | |
| 690 | ||
| 691 | return UNW_STEP_SUCCESS; | |
| 692 | } | |
| 693 | #endif // _LIBUNWIND_TARGET_AARCH64 | |
| 694 | ||
| 695 | ||
| 696 | } // namespace libunwind | |
| 697 | ||
| 698 | #endif // __COMPACT_UNWINDER_HPP__ |
libunwind/src/DwarfInstructions.hpp created+795| ... | ... | @@ -0,0 +1,795 @@ |
| 1 | //===-------------------------- DwarfInstructions.hpp ---------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is dual licensed under the MIT and the University of Illinois Open | |
| 6 | // Source Licenses. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | // | |
| 9 | // Processor specific interpretation of DWARF unwind info. | |
| 10 | // | |
| 11 | //===----------------------------------------------------------------------===// | |
| 12 | ||
| 13 | #ifndef __DWARF_INSTRUCTIONS_HPP__ | |
| 14 | #define __DWARF_INSTRUCTIONS_HPP__ | |
| 15 | ||
| 16 | #include <stdint.h> | |
| 17 | #include <stdio.h> | |
| 18 | #include <stdlib.h> | |
| 19 | ||
| 20 | #include "dwarf2.h" | |
| 21 | #include "Registers.hpp" | |
| 22 | #include "DwarfParser.hpp" | |
| 23 | #include "config.h" | |
| 24 | ||
| 25 | ||
| 26 | namespace libunwind { | |
| 27 | ||
| 28 | ||
| 29 | /// DwarfInstructions maps abtract DWARF unwind instructions to a particular | |
| 30 | /// architecture | |
| 31 | template <typename A, typename R> | |
| 32 | class DwarfInstructions { | |
| 33 | public: | |
| 34 | typedef typename A::pint_t pint_t; | |
| 35 | typedef typename A::sint_t sint_t; | |
| 36 | ||
| 37 | static int stepWithDwarf(A &addressSpace, pint_t pc, pint_t fdeStart, | |
| 38 | R &registers); | |
| 39 | ||
| 40 | private: | |
| 41 | ||
| 42 | enum { | |
| 43 | DW_X86_64_RET_ADDR = 16 | |
| 44 | }; | |
| 45 | ||
| 46 | enum { | |
| 47 | DW_X86_RET_ADDR = 8 | |
| 48 | }; | |
| 49 | ||
| 50 | typedef typename CFI_Parser<A>::RegisterLocation RegisterLocation; | |
| 51 | typedef typename CFI_Parser<A>::PrologInfo PrologInfo; | |
| 52 | typedef typename CFI_Parser<A>::FDE_Info FDE_Info; | |
| 53 | typedef typename CFI_Parser<A>::CIE_Info CIE_Info; | |
| 54 | ||
| 55 | static pint_t evaluateExpression(pint_t expression, A &addressSpace, | |
| 56 | const R &registers, | |
| 57 | pint_t initialStackValue); | |
| 58 | static pint_t getSavedRegister(A &addressSpace, const R &registers, | |
| 59 | pint_t cfa, const RegisterLocation &savedReg); | |
| 60 | static double getSavedFloatRegister(A &addressSpace, const R &registers, | |
| 61 | pint_t cfa, const RegisterLocation &savedReg); | |
| 62 | static v128 getSavedVectorRegister(A &addressSpace, const R &registers, | |
| 63 | pint_t cfa, const RegisterLocation &savedReg); | |
| 64 | ||
| 65 | static pint_t getCFA(A &addressSpace, const PrologInfo &prolog, | |
| 66 | const R &registers) { | |
| 67 | if (prolog.cfaRegister != 0) | |
| 68 | return (pint_t)((sint_t)registers.getRegister((int)prolog.cfaRegister) + | |
| 69 | prolog.cfaRegisterOffset); | |
| 70 | if (prolog.cfaExpression != 0) | |
| 71 | return evaluateExpression((pint_t)prolog.cfaExpression, addressSpace, | |
| 72 | registers, 0); | |
| 73 | assert(0 && "getCFA(): unknown location"); | |
| 74 | __builtin_unreachable(); | |
| 75 | } | |
| 76 | }; | |
| 77 | ||
| 78 | ||
| 79 | template <typename A, typename R> | |
| 80 | typename A::pint_t DwarfInstructions<A, R>::getSavedRegister( | |
| 81 | A &addressSpace, const R &registers, pint_t cfa, | |
| 82 | const RegisterLocation &savedReg) { | |
| 83 | switch (savedReg.location) { | |
| 84 | case CFI_Parser<A>::kRegisterInCFA: | |
| 85 | return addressSpace.getRegister(cfa + (pint_t)savedReg.value); | |
| 86 | ||
| 87 | case CFI_Parser<A>::kRegisterAtExpression: | |
| 88 | return addressSpace.getRegister( | |
| 89 | evaluateExpression((pint_t)savedReg.value, addressSpace, | |
| 90 | registers, cfa)); | |
| 91 | ||
| 92 | case CFI_Parser<A>::kRegisterIsExpression: | |
| 93 | return evaluateExpression((pint_t)savedReg.value, addressSpace, | |
| 94 | registers, cfa); | |
| 95 | ||
| 96 | case CFI_Parser<A>::kRegisterInRegister: | |
| 97 | return registers.getRegister((int)savedReg.value); | |
| 98 | ||
| 99 | case CFI_Parser<A>::kRegisterUnused: | |
| 100 | case CFI_Parser<A>::kRegisterOffsetFromCFA: | |
| 101 | // FIX ME | |
| 102 | break; | |
| 103 | } | |
| 104 | _LIBUNWIND_ABORT("unsupported restore location for register"); | |
| 105 | } | |
| 106 | ||
| 107 | template <typename A, typename R> | |
| 108 | double DwarfInstructions<A, R>::getSavedFloatRegister( | |
| 109 | A &addressSpace, const R &registers, pint_t cfa, | |
| 110 | const RegisterLocation &savedReg) { | |
| 111 | switch (savedReg.location) { | |
| 112 | case CFI_Parser<A>::kRegisterInCFA: | |
| 113 | return addressSpace.getDouble(cfa + (pint_t)savedReg.value); | |
| 114 | ||
| 115 | case CFI_Parser<A>::kRegisterAtExpression: | |
| 116 | return addressSpace.getDouble( | |
| 117 | evaluateExpression((pint_t)savedReg.value, addressSpace, | |
| 118 | registers, cfa)); | |
| 119 | ||
| 120 | case CFI_Parser<A>::kRegisterIsExpression: | |
| 121 | case CFI_Parser<A>::kRegisterUnused: | |
| 122 | case CFI_Parser<A>::kRegisterOffsetFromCFA: | |
| 123 | case CFI_Parser<A>::kRegisterInRegister: | |
| 124 | // FIX ME | |
| 125 | break; | |
| 126 | } | |
| 127 | _LIBUNWIND_ABORT("unsupported restore location for float register"); | |
| 128 | } | |
| 129 | ||
| 130 | template <typename A, typename R> | |
| 131 | v128 DwarfInstructions<A, R>::getSavedVectorRegister( | |
| 132 | A &addressSpace, const R &registers, pint_t cfa, | |
| 133 | const RegisterLocation &savedReg) { | |
| 134 | switch (savedReg.location) { | |
| 135 | case CFI_Parser<A>::kRegisterInCFA: | |
| 136 | return addressSpace.getVector(cfa + (pint_t)savedReg.value); | |
| 137 | ||
| 138 | case CFI_Parser<A>::kRegisterAtExpression: | |
| 139 | return addressSpace.getVector( | |
| 140 | evaluateExpression((pint_t)savedReg.value, addressSpace, | |
| 141 | registers, cfa)); | |
| 142 | ||
| 143 | case CFI_Parser<A>::kRegisterIsExpression: | |
| 144 | case CFI_Parser<A>::kRegisterUnused: | |
| 145 | case CFI_Parser<A>::kRegisterOffsetFromCFA: | |
| 146 | case CFI_Parser<A>::kRegisterInRegister: | |
| 147 | // FIX ME | |
| 148 | break; | |
| 149 | } | |
| 150 | _LIBUNWIND_ABORT("unsupported restore location for vector register"); | |
| 151 | } | |
| 152 | ||
| 153 | template <typename A, typename R> | |
| 154 | int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc, | |
| 155 | pint_t fdeStart, R &registers) { | |
| 156 | FDE_Info fdeInfo; | |
| 157 | CIE_Info cieInfo; | |
| 158 | if (CFI_Parser<A>::decodeFDE(addressSpace, fdeStart, &fdeInfo, | |
| 159 | &cieInfo) == NULL) { | |
| 160 | PrologInfo prolog; | |
| 161 | if (CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc, | |
| 162 | R::getArch(), &prolog)) { | |
| 163 | // get pointer to cfa (architecture specific) | |
| 164 | pint_t cfa = getCFA(addressSpace, prolog, registers); | |
| 165 | ||
| 166 | // restore registers that DWARF says were saved | |
| 167 | R newRegisters = registers; | |
| 168 | pint_t returnAddress = 0; | |
| 169 | const int lastReg = R::lastDwarfRegNum(); | |
| 170 | assert(static_cast<int>(CFI_Parser<A>::kMaxRegisterNumber) >= lastReg && | |
| 171 | "register range too large"); | |
| 172 | assert(lastReg >= (int)cieInfo.returnAddressRegister && | |
| 173 | "register range does not contain return address register"); | |
| 174 | for (int i = 0; i <= lastReg; ++i) { | |
| 175 | if (prolog.savedRegisters[i].location != | |
| 176 | CFI_Parser<A>::kRegisterUnused) { | |
| 177 | if (registers.validFloatRegister(i)) | |
| 178 | newRegisters.setFloatRegister( | |
| 179 | i, getSavedFloatRegister(addressSpace, registers, cfa, | |
| 180 | prolog.savedRegisters[i])); | |
| 181 | else if (registers.validVectorRegister(i)) | |
| 182 | newRegisters.setVectorRegister( | |
| 183 | i, getSavedVectorRegister(addressSpace, registers, cfa, | |
| 184 | prolog.savedRegisters[i])); | |
| 185 | else if (i == (int)cieInfo.returnAddressRegister) | |
| 186 | returnAddress = getSavedRegister(addressSpace, registers, cfa, | |
| 187 | prolog.savedRegisters[i]); | |
| 188 | else if (registers.validRegister(i)) | |
| 189 | newRegisters.setRegister( | |
| 190 | i, getSavedRegister(addressSpace, registers, cfa, | |
| 191 | prolog.savedRegisters[i])); | |
| 192 | else | |
| 193 | return UNW_EBADREG; | |
| 194 | } | |
| 195 | } | |
| 196 | ||
| 197 | // By definition, the CFA is the stack pointer at the call site, so | |
| 198 | // restoring SP means setting it to CFA. | |
| 199 | newRegisters.setSP(cfa); | |
| 200 | ||
| 201 | #if defined(_LIBUNWIND_TARGET_AARCH64) | |
| 202 | // If the target is aarch64 then the return address may have been signed | |
| 203 | // using the v8.3 pointer authentication extensions. The original | |
| 204 | // return address needs to be authenticated before the return address is | |
| 205 | // restored. autia1716 is used instead of autia as autia1716 assembles | |
| 206 | // to a NOP on pre-v8.3a architectures. | |
| 207 | if ((R::getArch() == REGISTERS_ARM64) && | |
| 208 | prolog.savedRegisters[UNW_ARM64_RA_SIGN_STATE].value) { | |
| 209 | #if !defined(_LIBUNWIND_IS_NATIVE_ONLY) | |
| 210 | return UNW_ECROSSRASIGNING; | |
| 211 | #else | |
| 212 | register unsigned long long x17 __asm("x17") = returnAddress; | |
| 213 | register unsigned long long x16 __asm("x16") = cfa; | |
| 214 | ||
| 215 | // These are the autia1716/autib1716 instructions. The hint instructions | |
| 216 | // are used here as gcc does not assemble autia1716/autib1716 for pre | |
| 217 | // armv8.3a targets. | |
| 218 | if (cieInfo.addressesSignedWithBKey) | |
| 219 | asm("hint 0xe" : "+r"(x17) : "r"(x16)); // autib1716 | |
| 220 | else | |
| 221 | asm("hint 0xc" : "+r"(x17) : "r"(x16)); // autia1716 | |
| 222 | returnAddress = x17; | |
| 223 | #endif | |
| 224 | } | |
| 225 | #endif | |
| 226 | ||
| 227 | #if defined(_LIBUNWIND_TARGET_SPARC) | |
| 228 | if (R::getArch() == REGISTERS_SPARC) { | |
| 229 | // Skip call site instruction and delay slot | |
| 230 | returnAddress += 8; | |
| 231 | // Skip unimp instruction if function returns a struct | |
| 232 | if ((addressSpace.get32(returnAddress) & 0xC1C00000) == 0) | |
| 233 | returnAddress += 4; | |
| 234 | } | |
| 235 | #endif | |
| 236 | ||
| 237 | // Return address is address after call site instruction, so setting IP to | |
| 238 | // that does simualates a return. | |
| 239 | newRegisters.setIP(returnAddress); | |
| 240 | ||
| 241 | // Simulate the step by replacing the register set with the new ones. | |
| 242 | registers = newRegisters; | |
| 243 | ||
| 244 | return UNW_STEP_SUCCESS; | |
| 245 | } | |
| 246 | } | |
| 247 | return UNW_EBADFRAME; | |
| 248 | } | |
| 249 | ||
| 250 | template <typename A, typename R> | |
| 251 | typename A::pint_t | |
| 252 | DwarfInstructions<A, R>::evaluateExpression(pint_t expression, A &addressSpace, | |
| 253 | const R &registers, | |
| 254 | pint_t initialStackValue) { | |
| 255 | const bool log = false; | |
| 256 | pint_t p = expression; | |
| 257 | pint_t expressionEnd = expression + 20; // temp, until len read | |
| 258 | pint_t length = (pint_t)addressSpace.getULEB128(p, expressionEnd); | |
| 259 | expressionEnd = p + length; | |
| 260 | if (log) | |
| 261 | fprintf(stderr, "evaluateExpression(): length=%" PRIu64 "\n", | |
| 262 | (uint64_t)length); | |
| 263 | pint_t stack[100]; | |
| 264 | pint_t *sp = stack; | |
| 265 | *(++sp) = initialStackValue; | |
| 266 | ||
| 267 | while (p < expressionEnd) { | |
| 268 | if (log) { | |
| 269 | for (pint_t *t = sp; t > stack; --t) { | |
| 270 | fprintf(stderr, "sp[] = 0x%" PRIx64 "\n", (uint64_t)(*t)); | |
| 271 | } | |
| 272 | } | |
| 273 | uint8_t opcode = addressSpace.get8(p++); | |
| 274 | sint_t svalue, svalue2; | |
| 275 | pint_t value; | |
| 276 | uint32_t reg; | |
| 277 | switch (opcode) { | |
| 278 | case DW_OP_addr: | |
| 279 | // push immediate address sized value | |
| 280 | value = addressSpace.getP(p); | |
| 281 | p += sizeof(pint_t); | |
| 282 | *(++sp) = value; | |
| 283 | if (log) | |
| 284 | fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value); | |
| 285 | break; | |
| 286 | ||
| 287 | case DW_OP_deref: | |
| 288 | // pop stack, dereference, push result | |
| 289 | value = *sp--; | |
| 290 | *(++sp) = addressSpace.getP(value); | |
| 291 | if (log) | |
| 292 | fprintf(stderr, "dereference 0x%" PRIx64 "\n", (uint64_t)value); | |
| 293 | break; | |
| 294 | ||
| 295 | case DW_OP_const1u: | |
| 296 | // push immediate 1 byte value | |
| 297 | value = addressSpace.get8(p); | |
| 298 | p += 1; | |
| 299 | *(++sp) = value; | |
| 300 | if (log) | |
| 301 | fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value); | |
| 302 | break; | |
| 303 | ||
| 304 | case DW_OP_const1s: | |
| 305 | // push immediate 1 byte signed value | |
| 306 | svalue = (int8_t) addressSpace.get8(p); | |
| 307 | p += 1; | |
| 308 | *(++sp) = (pint_t)svalue; | |
| 309 | if (log) | |
| 310 | fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue); | |
| 311 | break; | |
| 312 | ||
| 313 | case DW_OP_const2u: | |
| 314 | // push immediate 2 byte value | |
| 315 | value = addressSpace.get16(p); | |
| 316 | p += 2; | |
| 317 | *(++sp) = value; | |
| 318 | if (log) | |
| 319 | fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value); | |
| 320 | break; | |
| 321 | ||
| 322 | case DW_OP_const2s: | |
| 323 | // push immediate 2 byte signed value | |
| 324 | svalue = (int16_t) addressSpace.get16(p); | |
| 325 | p += 2; | |
| 326 | *(++sp) = (pint_t)svalue; | |
| 327 | if (log) | |
| 328 | fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue); | |
| 329 | break; | |
| 330 | ||
| 331 | case DW_OP_const4u: | |
| 332 | // push immediate 4 byte value | |
| 333 | value = addressSpace.get32(p); | |
| 334 | p += 4; | |
| 335 | *(++sp) = value; | |
| 336 | if (log) | |
| 337 | fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value); | |
| 338 | break; | |
| 339 | ||
| 340 | case DW_OP_const4s: | |
| 341 | // push immediate 4 byte signed value | |
| 342 | svalue = (int32_t)addressSpace.get32(p); | |
| 343 | p += 4; | |
| 344 | *(++sp) = (pint_t)svalue; | |
| 345 | if (log) | |
| 346 | fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue); | |
| 347 | break; | |
| 348 | ||
| 349 | case DW_OP_const8u: | |
| 350 | // push immediate 8 byte value | |
| 351 | value = (pint_t)addressSpace.get64(p); | |
| 352 | p += 8; | |
| 353 | *(++sp) = value; | |
| 354 | if (log) | |
| 355 | fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value); | |
| 356 | break; | |
| 357 | ||
| 358 | case DW_OP_const8s: | |
| 359 | // push immediate 8 byte signed value | |
| 360 | value = (pint_t)addressSpace.get64(p); | |
| 361 | p += 8; | |
| 362 | *(++sp) = value; | |
| 363 | if (log) | |
| 364 | fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value); | |
| 365 | break; | |
| 366 | ||
| 367 | case DW_OP_constu: | |
| 368 | // push immediate ULEB128 value | |
| 369 | value = (pint_t)addressSpace.getULEB128(p, expressionEnd); | |
| 370 | *(++sp) = value; | |
| 371 | if (log) | |
| 372 | fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value); | |
| 373 | break; | |
| 374 | ||
| 375 | case DW_OP_consts: | |
| 376 | // push immediate SLEB128 value | |
| 377 | svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd); | |
| 378 | *(++sp) = (pint_t)svalue; | |
| 379 | if (log) | |
| 380 | fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue); | |
| 381 | break; | |
| 382 | ||
| 383 | case DW_OP_dup: | |
| 384 | // push top of stack | |
| 385 | value = *sp; | |
| 386 | *(++sp) = value; | |
| 387 | if (log) | |
| 388 | fprintf(stderr, "duplicate top of stack\n"); | |
| 389 | break; | |
| 390 | ||
| 391 | case DW_OP_drop: | |
| 392 | // pop | |
| 393 | --sp; | |
| 394 | if (log) | |
| 395 | fprintf(stderr, "pop top of stack\n"); | |
| 396 | break; | |
| 397 | ||
| 398 | case DW_OP_over: | |
| 399 | // dup second | |
| 400 | value = sp[-1]; | |
| 401 | *(++sp) = value; | |
| 402 | if (log) | |
| 403 | fprintf(stderr, "duplicate second in stack\n"); | |
| 404 | break; | |
| 405 | ||
| 406 | case DW_OP_pick: | |
| 407 | // pick from | |
| 408 | reg = addressSpace.get8(p); | |
| 409 | p += 1; | |
| 410 | value = sp[-reg]; | |
| 411 | *(++sp) = value; | |
| 412 | if (log) | |
| 413 | fprintf(stderr, "duplicate %d in stack\n", reg); | |
| 414 | break; | |
| 415 | ||
| 416 | case DW_OP_swap: | |
| 417 | // swap top two | |
| 418 | value = sp[0]; | |
| 419 | sp[0] = sp[-1]; | |
| 420 | sp[-1] = value; | |
| 421 | if (log) | |
| 422 | fprintf(stderr, "swap top of stack\n"); | |
| 423 | break; | |
| 424 | ||
| 425 | case DW_OP_rot: | |
| 426 | // rotate top three | |
| 427 | value = sp[0]; | |
| 428 | sp[0] = sp[-1]; | |
| 429 | sp[-1] = sp[-2]; | |
| 430 | sp[-2] = value; | |
| 431 | if (log) | |
| 432 | fprintf(stderr, "rotate top three of stack\n"); | |
| 433 | break; | |
| 434 | ||
| 435 | case DW_OP_xderef: | |
| 436 | // pop stack, dereference, push result | |
| 437 | value = *sp--; | |
| 438 | *sp = *((pint_t*)value); | |
| 439 | if (log) | |
| 440 | fprintf(stderr, "x-dereference 0x%" PRIx64 "\n", (uint64_t)value); | |
| 441 | break; | |
| 442 | ||
| 443 | case DW_OP_abs: | |
| 444 | svalue = (sint_t)*sp; | |
| 445 | if (svalue < 0) | |
| 446 | *sp = (pint_t)(-svalue); | |
| 447 | if (log) | |
| 448 | fprintf(stderr, "abs\n"); | |
| 449 | break; | |
| 450 | ||
| 451 | case DW_OP_and: | |
| 452 | value = *sp--; | |
| 453 | *sp &= value; | |
| 454 | if (log) | |
| 455 | fprintf(stderr, "and\n"); | |
| 456 | break; | |
| 457 | ||
| 458 | case DW_OP_div: | |
| 459 | svalue = (sint_t)(*sp--); | |
| 460 | svalue2 = (sint_t)*sp; | |
| 461 | *sp = (pint_t)(svalue2 / svalue); | |
| 462 | if (log) | |
| 463 | fprintf(stderr, "div\n"); | |
| 464 | break; | |
| 465 | ||
| 466 | case DW_OP_minus: | |
| 467 | value = *sp--; | |
| 468 | *sp = *sp - value; | |
| 469 | if (log) | |
| 470 | fprintf(stderr, "minus\n"); | |
| 471 | break; | |
| 472 | ||
| 473 | case DW_OP_mod: | |
| 474 | svalue = (sint_t)(*sp--); | |
| 475 | svalue2 = (sint_t)*sp; | |
| 476 | *sp = (pint_t)(svalue2 % svalue); | |
| 477 | if (log) | |
| 478 | fprintf(stderr, "module\n"); | |
| 479 | break; | |
| 480 | ||
| 481 | case DW_OP_mul: | |
| 482 | svalue = (sint_t)(*sp--); | |
| 483 | svalue2 = (sint_t)*sp; | |
| 484 | *sp = (pint_t)(svalue2 * svalue); | |
| 485 | if (log) | |
| 486 | fprintf(stderr, "mul\n"); | |
| 487 | break; | |
| 488 | ||
| 489 | case DW_OP_neg: | |
| 490 | *sp = 0 - *sp; | |
| 491 | if (log) | |
| 492 | fprintf(stderr, "neg\n"); | |
| 493 | break; | |
| 494 | ||
| 495 | case DW_OP_not: | |
| 496 | svalue = (sint_t)(*sp); | |
| 497 | *sp = (pint_t)(~svalue); | |
| 498 | if (log) | |
| 499 | fprintf(stderr, "not\n"); | |
| 500 | break; | |
| 501 | ||
| 502 | case DW_OP_or: | |
| 503 | value = *sp--; | |
| 504 | *sp |= value; | |
| 505 | if (log) | |
| 506 | fprintf(stderr, "or\n"); | |
| 507 | break; | |
| 508 | ||
| 509 | case DW_OP_plus: | |
| 510 | value = *sp--; | |
| 511 | *sp += value; | |
| 512 | if (log) | |
| 513 | fprintf(stderr, "plus\n"); | |
| 514 | break; | |
| 515 | ||
| 516 | case DW_OP_plus_uconst: | |
| 517 | // pop stack, add uelb128 constant, push result | |
| 518 | *sp += static_cast<pint_t>(addressSpace.getULEB128(p, expressionEnd)); | |
| 519 | if (log) | |
| 520 | fprintf(stderr, "add constant\n"); | |
| 521 | break; | |
| 522 | ||
| 523 | case DW_OP_shl: | |
| 524 | value = *sp--; | |
| 525 | *sp = *sp << value; | |
| 526 | if (log) | |
| 527 | fprintf(stderr, "shift left\n"); | |
| 528 | break; | |
| 529 | ||
| 530 | case DW_OP_shr: | |
| 531 | value = *sp--; | |
| 532 | *sp = *sp >> value; | |
| 533 | if (log) | |
| 534 | fprintf(stderr, "shift left\n"); | |
| 535 | break; | |
| 536 | ||
| 537 | case DW_OP_shra: | |
| 538 | value = *sp--; | |
| 539 | svalue = (sint_t)*sp; | |
| 540 | *sp = (pint_t)(svalue >> value); | |
| 541 | if (log) | |
| 542 | fprintf(stderr, "shift left arithmetric\n"); | |
| 543 | break; | |
| 544 | ||
| 545 | case DW_OP_xor: | |
| 546 | value = *sp--; | |
| 547 | *sp ^= value; | |
| 548 | if (log) | |
| 549 | fprintf(stderr, "xor\n"); | |
| 550 | break; | |
| 551 | ||
| 552 | case DW_OP_skip: | |
| 553 | svalue = (int16_t) addressSpace.get16(p); | |
| 554 | p += 2; | |
| 555 | p = (pint_t)((sint_t)p + svalue); | |
| 556 | if (log) | |
| 557 | fprintf(stderr, "skip %" PRIu64 "\n", (uint64_t)svalue); | |
| 558 | break; | |
| 559 | ||
| 560 | case DW_OP_bra: | |
| 561 | svalue = (int16_t) addressSpace.get16(p); | |
| 562 | p += 2; | |
| 563 | if (*sp--) | |
| 564 | p = (pint_t)((sint_t)p + svalue); | |
| 565 | if (log) | |
| 566 | fprintf(stderr, "bra %" PRIu64 "\n", (uint64_t)svalue); | |
| 567 | break; | |
| 568 | ||
| 569 | case DW_OP_eq: | |
| 570 | value = *sp--; | |
| 571 | *sp = (*sp == value); | |
| 572 | if (log) | |
| 573 | fprintf(stderr, "eq\n"); | |
| 574 | break; | |
| 575 | ||
| 576 | case DW_OP_ge: | |
| 577 | value = *sp--; | |
| 578 | *sp = (*sp >= value); | |
| 579 | if (log) | |
| 580 | fprintf(stderr, "ge\n"); | |
| 581 | break; | |
| 582 | ||
| 583 | case DW_OP_gt: | |
| 584 | value = *sp--; | |
| 585 | *sp = (*sp > value); | |
| 586 | if (log) | |
| 587 | fprintf(stderr, "gt\n"); | |
| 588 | break; | |
| 589 | ||
| 590 | case DW_OP_le: | |
| 591 | value = *sp--; | |
| 592 | *sp = (*sp <= value); | |
| 593 | if (log) | |
| 594 | fprintf(stderr, "le\n"); | |
| 595 | break; | |
| 596 | ||
| 597 | case DW_OP_lt: | |
| 598 | value = *sp--; | |
| 599 | *sp = (*sp < value); | |
| 600 | if (log) | |
| 601 | fprintf(stderr, "lt\n"); | |
| 602 | break; | |
| 603 | ||
| 604 | case DW_OP_ne: | |
| 605 | value = *sp--; | |
| 606 | *sp = (*sp != value); | |
| 607 | if (log) | |
| 608 | fprintf(stderr, "ne\n"); | |
| 609 | break; | |
| 610 | ||
| 611 | case DW_OP_lit0: | |
| 612 | case DW_OP_lit1: | |
| 613 | case DW_OP_lit2: | |
| 614 | case DW_OP_lit3: | |
| 615 | case DW_OP_lit4: | |
| 616 | case DW_OP_lit5: | |
| 617 | case DW_OP_lit6: | |
| 618 | case DW_OP_lit7: | |
| 619 | case DW_OP_lit8: | |
| 620 | case DW_OP_lit9: | |
| 621 | case DW_OP_lit10: | |
| 622 | case DW_OP_lit11: | |
| 623 | case DW_OP_lit12: | |
| 624 | case DW_OP_lit13: | |
| 625 | case DW_OP_lit14: | |
| 626 | case DW_OP_lit15: | |
| 627 | case DW_OP_lit16: | |
| 628 | case DW_OP_lit17: | |
| 629 | case DW_OP_lit18: | |
| 630 | case DW_OP_lit19: | |
| 631 | case DW_OP_lit20: | |
| 632 | case DW_OP_lit21: | |
| 633 | case DW_OP_lit22: | |
| 634 | case DW_OP_lit23: | |
| 635 | case DW_OP_lit24: | |
| 636 | case DW_OP_lit25: | |
| 637 | case DW_OP_lit26: | |
| 638 | case DW_OP_lit27: | |
| 639 | case DW_OP_lit28: | |
| 640 | case DW_OP_lit29: | |
| 641 | case DW_OP_lit30: | |
| 642 | case DW_OP_lit31: | |
| 643 | value = static_cast<pint_t>(opcode - DW_OP_lit0); | |
| 644 | *(++sp) = value; | |
| 645 | if (log) | |
| 646 | fprintf(stderr, "push literal 0x%" PRIx64 "\n", (uint64_t)value); | |
| 647 | break; | |
| 648 | ||
| 649 | case DW_OP_reg0: | |
| 650 | case DW_OP_reg1: | |
| 651 | case DW_OP_reg2: | |
| 652 | case DW_OP_reg3: | |
| 653 | case DW_OP_reg4: | |
| 654 | case DW_OP_reg5: | |
| 655 | case DW_OP_reg6: | |
| 656 | case DW_OP_reg7: | |
| 657 | case DW_OP_reg8: | |
| 658 | case DW_OP_reg9: | |
| 659 | case DW_OP_reg10: | |
| 660 | case DW_OP_reg11: | |
| 661 | case DW_OP_reg12: | |
| 662 | case DW_OP_reg13: | |
| 663 | case DW_OP_reg14: | |
| 664 | case DW_OP_reg15: | |
| 665 | case DW_OP_reg16: | |
| 666 | case DW_OP_reg17: | |
| 667 | case DW_OP_reg18: | |
| 668 | case DW_OP_reg19: | |
| 669 | case DW_OP_reg20: | |
| 670 | case DW_OP_reg21: | |
| 671 | case DW_OP_reg22: | |
| 672 | case DW_OP_reg23: | |
| 673 | case DW_OP_reg24: | |
| 674 | case DW_OP_reg25: | |
| 675 | case DW_OP_reg26: | |
| 676 | case DW_OP_reg27: | |
| 677 | case DW_OP_reg28: | |
| 678 | case DW_OP_reg29: | |
| 679 | case DW_OP_reg30: | |
| 680 | case DW_OP_reg31: | |
| 681 | reg = static_cast<uint32_t>(opcode - DW_OP_reg0); | |
| 682 | *(++sp) = registers.getRegister((int)reg); | |
| 683 | if (log) | |
| 684 | fprintf(stderr, "push reg %d\n", reg); | |
| 685 | break; | |
| 686 | ||
| 687 | case DW_OP_regx: | |
| 688 | reg = static_cast<uint32_t>(addressSpace.getULEB128(p, expressionEnd)); | |
| 689 | *(++sp) = registers.getRegister((int)reg); | |
| 690 | if (log) | |
| 691 | fprintf(stderr, "push reg %d + 0x%" PRIx64 "\n", reg, (uint64_t)svalue); | |
| 692 | break; | |
| 693 | ||
| 694 | case DW_OP_breg0: | |
| 695 | case DW_OP_breg1: | |
| 696 | case DW_OP_breg2: | |
| 697 | case DW_OP_breg3: | |
| 698 | case DW_OP_breg4: | |
| 699 | case DW_OP_breg5: | |
| 700 | case DW_OP_breg6: | |
| 701 | case DW_OP_breg7: | |
| 702 | case DW_OP_breg8: | |
| 703 | case DW_OP_breg9: | |
| 704 | case DW_OP_breg10: | |
| 705 | case DW_OP_breg11: | |
| 706 | case DW_OP_breg12: | |
| 707 | case DW_OP_breg13: | |
| 708 | case DW_OP_breg14: | |
| 709 | case DW_OP_breg15: | |
| 710 | case DW_OP_breg16: | |
| 711 | case DW_OP_breg17: | |
| 712 | case DW_OP_breg18: | |
| 713 | case DW_OP_breg19: | |
| 714 | case DW_OP_breg20: | |
| 715 | case DW_OP_breg21: | |
| 716 | case DW_OP_breg22: | |
| 717 | case DW_OP_breg23: | |
| 718 | case DW_OP_breg24: | |
| 719 | case DW_OP_breg25: | |
| 720 | case DW_OP_breg26: | |
| 721 | case DW_OP_breg27: | |
| 722 | case DW_OP_breg28: | |
| 723 | case DW_OP_breg29: | |
| 724 | case DW_OP_breg30: | |
| 725 | case DW_OP_breg31: | |
| 726 | reg = static_cast<uint32_t>(opcode - DW_OP_breg0); | |
| 727 | svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd); | |
| 728 | svalue += static_cast<sint_t>(registers.getRegister((int)reg)); | |
| 729 | *(++sp) = (pint_t)(svalue); | |
| 730 | if (log) | |
| 731 | fprintf(stderr, "push reg %d + 0x%" PRIx64 "\n", reg, (uint64_t)svalue); | |
| 732 | break; | |
| 733 | ||
| 734 | case DW_OP_bregx: | |
| 735 | reg = static_cast<uint32_t>(addressSpace.getULEB128(p, expressionEnd)); | |
| 736 | svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd); | |
| 737 | svalue += static_cast<sint_t>(registers.getRegister((int)reg)); | |
| 738 | *(++sp) = (pint_t)(svalue); | |
| 739 | if (log) | |
| 740 | fprintf(stderr, "push reg %d + 0x%" PRIx64 "\n", reg, (uint64_t)svalue); | |
| 741 | break; | |
| 742 | ||
| 743 | case DW_OP_fbreg: | |
| 744 | _LIBUNWIND_ABORT("DW_OP_fbreg not implemented"); | |
| 745 | break; | |
| 746 | ||
| 747 | case DW_OP_piece: | |
| 748 | _LIBUNWIND_ABORT("DW_OP_piece not implemented"); | |
| 749 | break; | |
| 750 | ||
| 751 | case DW_OP_deref_size: | |
| 752 | // pop stack, dereference, push result | |
| 753 | value = *sp--; | |
| 754 | switch (addressSpace.get8(p++)) { | |
| 755 | case 1: | |
| 756 | value = addressSpace.get8(value); | |
| 757 | break; | |
| 758 | case 2: | |
| 759 | value = addressSpace.get16(value); | |
| 760 | break; | |
| 761 | case 4: | |
| 762 | value = addressSpace.get32(value); | |
| 763 | break; | |
| 764 | case 8: | |
| 765 | value = (pint_t)addressSpace.get64(value); | |
| 766 | break; | |
| 767 | default: | |
| 768 | _LIBUNWIND_ABORT("DW_OP_deref_size with bad size"); | |
| 769 | } | |
| 770 | *(++sp) = value; | |
| 771 | if (log) | |
| 772 | fprintf(stderr, "sized dereference 0x%" PRIx64 "\n", (uint64_t)value); | |
| 773 | break; | |
| 774 | ||
| 775 | case DW_OP_xderef_size: | |
| 776 | case DW_OP_nop: | |
| 777 | case DW_OP_push_object_addres: | |
| 778 | case DW_OP_call2: | |
| 779 | case DW_OP_call4: | |
| 780 | case DW_OP_call_ref: | |
| 781 | default: | |
| 782 | _LIBUNWIND_ABORT("DWARF opcode not implemented"); | |
| 783 | } | |
| 784 | ||
| 785 | } | |
| 786 | if (log) | |
| 787 | fprintf(stderr, "expression evaluates to 0x%" PRIx64 "\n", (uint64_t)*sp); | |
| 788 | return *sp; | |
| 789 | } | |
| 790 | ||
| 791 | ||
| 792 | ||
| 793 | } // namespace libunwind | |
| 794 | ||
| 795 | #endif // __DWARF_INSTRUCTIONS_HPP__ |
libunwind/src/DwarfParser.hpp created+766| ... | ... | @@ -0,0 +1,766 @@ |
| 1 | //===--------------------------- DwarfParser.hpp --------------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is dual licensed under the MIT and the University of Illinois Open | |
| 6 | // Source Licenses. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | // | |
| 9 | // Parses DWARF CFIs (FDEs and CIEs). | |
| 10 | // | |
| 11 | //===----------------------------------------------------------------------===// | |
| 12 | ||
| 13 | #ifndef __DWARF_PARSER_HPP__ | |
| 14 | #define __DWARF_PARSER_HPP__ | |
| 15 | ||
| 16 | #include <inttypes.h> | |
| 17 | #include <stdint.h> | |
| 18 | #include <stdio.h> | |
| 19 | #include <stdlib.h> | |
| 20 | ||
| 21 | #include "libunwind.h" | |
| 22 | #include "dwarf2.h" | |
| 23 | #include "Registers.hpp" | |
| 24 | ||
| 25 | #include "config.h" | |
| 26 | ||
| 27 | namespace libunwind { | |
| 28 | ||
| 29 | /// CFI_Parser does basic parsing of a CFI (Call Frame Information) records. | |
| 30 | /// See DWARF Spec for details: | |
| 31 | /// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html | |
| 32 | /// | |
| 33 | template <typename A> | |
| 34 | class CFI_Parser { | |
| 35 | public: | |
| 36 | typedef typename A::pint_t pint_t; | |
| 37 | ||
| 38 | /// Information encoded in a CIE (Common Information Entry) | |
| 39 | struct CIE_Info { | |
| 40 | pint_t cieStart; | |
| 41 | pint_t cieLength; | |
| 42 | pint_t cieInstructions; | |
| 43 | uint8_t pointerEncoding; | |
| 44 | uint8_t lsdaEncoding; | |
| 45 | uint8_t personalityEncoding; | |
| 46 | uint8_t personalityOffsetInCIE; | |
| 47 | pint_t personality; | |
| 48 | uint32_t codeAlignFactor; | |
| 49 | int dataAlignFactor; | |
| 50 | bool isSignalFrame; | |
| 51 | bool fdesHaveAugmentationData; | |
| 52 | uint8_t returnAddressRegister; | |
| 53 | #if defined(_LIBUNWIND_TARGET_AARCH64) | |
| 54 | bool addressesSignedWithBKey; | |
| 55 | #endif | |
| 56 | }; | |
| 57 | ||
| 58 | /// Information about an FDE (Frame Description Entry) | |
| 59 | struct FDE_Info { | |
| 60 | pint_t fdeStart; | |
| 61 | pint_t fdeLength; | |
| 62 | pint_t fdeInstructions; | |
| 63 | pint_t pcStart; | |
| 64 | pint_t pcEnd; | |
| 65 | pint_t lsda; | |
| 66 | }; | |
| 67 | ||
| 68 | enum { | |
| 69 | kMaxRegisterNumber = _LIBUNWIND_HIGHEST_DWARF_REGISTER | |
| 70 | }; | |
| 71 | enum RegisterSavedWhere { | |
| 72 | kRegisterUnused, | |
| 73 | kRegisterInCFA, | |
| 74 | kRegisterOffsetFromCFA, | |
| 75 | kRegisterInRegister, | |
| 76 | kRegisterAtExpression, | |
| 77 | kRegisterIsExpression | |
| 78 | }; | |
| 79 | struct RegisterLocation { | |
| 80 | RegisterSavedWhere location; | |
| 81 | int64_t value; | |
| 82 | }; | |
| 83 | /// Information about a frame layout and registers saved determined | |
| 84 | /// by "running" the DWARF FDE "instructions" | |
| 85 | struct PrologInfo { | |
| 86 | uint32_t cfaRegister; | |
| 87 | int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset | |
| 88 | int64_t cfaExpression; // CFA = expression | |
| 89 | uint32_t spExtraArgSize; | |
| 90 | uint32_t codeOffsetAtStackDecrement; | |
| 91 | bool registersInOtherRegisters; | |
| 92 | bool sameValueUsed; | |
| 93 | RegisterLocation savedRegisters[kMaxRegisterNumber + 1]; | |
| 94 | }; | |
| 95 | ||
| 96 | struct PrologInfoStackEntry { | |
| 97 | PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i) | |
| 98 | : next(n), info(i) {} | |
| 99 | PrologInfoStackEntry *next; | |
| 100 | PrologInfo info; | |
| 101 | }; | |
| 102 | ||
| 103 | static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, | |
| 104 | uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo, | |
| 105 | CIE_Info *cieInfo); | |
| 106 | static const char *decodeFDE(A &addressSpace, pint_t fdeStart, | |
| 107 | FDE_Info *fdeInfo, CIE_Info *cieInfo); | |
| 108 | static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo, | |
| 109 | const CIE_Info &cieInfo, pint_t upToPC, | |
| 110 | int arch, PrologInfo *results); | |
| 111 | ||
| 112 | static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo); | |
| 113 | ||
| 114 | private: | |
| 115 | static bool parseInstructions(A &addressSpace, pint_t instructions, | |
| 116 | pint_t instructionsEnd, const CIE_Info &cieInfo, | |
| 117 | pint_t pcoffset, | |
| 118 | PrologInfoStackEntry *&rememberStack, int arch, | |
| 119 | PrologInfo *results); | |
| 120 | }; | |
| 121 | ||
| 122 | /// Parse a FDE into a CIE_Info and an FDE_Info | |
| 123 | template <typename A> | |
| 124 | const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart, | |
| 125 | FDE_Info *fdeInfo, CIE_Info *cieInfo) { | |
| 126 | pint_t p = fdeStart; | |
| 127 | pint_t cfiLength = (pint_t)addressSpace.get32(p); | |
| 128 | p += 4; | |
| 129 | if (cfiLength == 0xffffffff) { | |
| 130 | // 0xffffffff means length is really next 8 bytes | |
| 131 | cfiLength = (pint_t)addressSpace.get64(p); | |
| 132 | p += 8; | |
| 133 | } | |
| 134 | if (cfiLength == 0) | |
| 135 | return "FDE has zero length"; // end marker | |
| 136 | uint32_t ciePointer = addressSpace.get32(p); | |
| 137 | if (ciePointer == 0) | |
| 138 | return "FDE is really a CIE"; // this is a CIE not an FDE | |
| 139 | pint_t nextCFI = p + cfiLength; | |
| 140 | pint_t cieStart = p - ciePointer; | |
| 141 | const char *err = parseCIE(addressSpace, cieStart, cieInfo); | |
| 142 | if (err != NULL) | |
| 143 | return err; | |
| 144 | p += 4; | |
| 145 | // Parse pc begin and range. | |
| 146 | pint_t pcStart = | |
| 147 | addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding); | |
| 148 | pint_t pcRange = | |
| 149 | addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F); | |
| 150 | // Parse rest of info. | |
| 151 | fdeInfo->lsda = 0; | |
| 152 | // Check for augmentation length. | |
| 153 | if (cieInfo->fdesHaveAugmentationData) { | |
| 154 | pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI); | |
| 155 | pint_t endOfAug = p + augLen; | |
| 156 | if (cieInfo->lsdaEncoding != DW_EH_PE_omit) { | |
| 157 | // Peek at value (without indirection). Zero means no LSDA. | |
| 158 | pint_t lsdaStart = p; | |
| 159 | if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != | |
| 160 | 0) { | |
| 161 | // Reset pointer and re-parse LSDA address. | |
| 162 | p = lsdaStart; | |
| 163 | fdeInfo->lsda = | |
| 164 | addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); | |
| 165 | } | |
| 166 | } | |
| 167 | p = endOfAug; | |
| 168 | } | |
| 169 | fdeInfo->fdeStart = fdeStart; | |
| 170 | fdeInfo->fdeLength = nextCFI - fdeStart; | |
| 171 | fdeInfo->fdeInstructions = p; | |
| 172 | fdeInfo->pcStart = pcStart; | |
| 173 | fdeInfo->pcEnd = pcStart + pcRange; | |
| 174 | return NULL; // success | |
| 175 | } | |
| 176 | ||
| 177 | /// Scan an eh_frame section to find an FDE for a pc | |
| 178 | template <typename A> | |
| 179 | bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, | |
| 180 | uint32_t sectionLength, pint_t fdeHint, | |
| 181 | FDE_Info *fdeInfo, CIE_Info *cieInfo) { | |
| 182 | //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc); | |
| 183 | pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart; | |
| 184 | const pint_t ehSectionEnd = p + sectionLength; | |
| 185 | while (p < ehSectionEnd) { | |
| 186 | pint_t currentCFI = p; | |
| 187 | //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p); | |
| 188 | pint_t cfiLength = addressSpace.get32(p); | |
| 189 | p += 4; | |
| 190 | if (cfiLength == 0xffffffff) { | |
| 191 | // 0xffffffff means length is really next 8 bytes | |
| 192 | cfiLength = (pint_t)addressSpace.get64(p); | |
| 193 | p += 8; | |
| 194 | } | |
| 195 | if (cfiLength == 0) | |
| 196 | return false; // end marker | |
| 197 | uint32_t id = addressSpace.get32(p); | |
| 198 | if (id == 0) { | |
| 199 | // Skip over CIEs. | |
| 200 | p += cfiLength; | |
| 201 | } else { | |
| 202 | // Process FDE to see if it covers pc. | |
| 203 | pint_t nextCFI = p + cfiLength; | |
| 204 | uint32_t ciePointer = addressSpace.get32(p); | |
| 205 | pint_t cieStart = p - ciePointer; | |
| 206 | // Validate pointer to CIE is within section. | |
| 207 | if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) { | |
| 208 | if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) { | |
| 209 | p += 4; | |
| 210 | // Parse pc begin and range. | |
| 211 | pint_t pcStart = | |
| 212 | addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding); | |
| 213 | pint_t pcRange = addressSpace.getEncodedP( | |
| 214 | p, nextCFI, cieInfo->pointerEncoding & 0x0F); | |
| 215 | // Test if pc is within the function this FDE covers. | |
| 216 | if ((pcStart < pc) && (pc <= pcStart + pcRange)) { | |
| 217 | // parse rest of info | |
| 218 | fdeInfo->lsda = 0; | |
| 219 | // check for augmentation length | |
| 220 | if (cieInfo->fdesHaveAugmentationData) { | |
| 221 | pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI); | |
| 222 | pint_t endOfAug = p + augLen; | |
| 223 | if (cieInfo->lsdaEncoding != DW_EH_PE_omit) { | |
| 224 | // Peek at value (without indirection). Zero means no LSDA. | |
| 225 | pint_t lsdaStart = p; | |
| 226 | if (addressSpace.getEncodedP( | |
| 227 | p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) { | |
| 228 | // Reset pointer and re-parse LSDA address. | |
| 229 | p = lsdaStart; | |
| 230 | fdeInfo->lsda = addressSpace | |
| 231 | .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); | |
| 232 | } | |
| 233 | } | |
| 234 | p = endOfAug; | |
| 235 | } | |
| 236 | fdeInfo->fdeStart = currentCFI; | |
| 237 | fdeInfo->fdeLength = nextCFI - currentCFI; | |
| 238 | fdeInfo->fdeInstructions = p; | |
| 239 | fdeInfo->pcStart = pcStart; | |
| 240 | fdeInfo->pcEnd = pcStart + pcRange; | |
| 241 | return true; | |
| 242 | } else { | |
| 243 | // pc is not in begin/range, skip this FDE | |
| 244 | } | |
| 245 | } else { | |
| 246 | // Malformed CIE, now augmentation describing pc range encoding. | |
| 247 | } | |
| 248 | } else { | |
| 249 | // malformed FDE. CIE is bad | |
| 250 | } | |
| 251 | p = nextCFI; | |
| 252 | } | |
| 253 | } | |
| 254 | return false; | |
| 255 | } | |
| 256 | ||
| 257 | /// Extract info from a CIE | |
| 258 | template <typename A> | |
| 259 | const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie, | |
| 260 | CIE_Info *cieInfo) { | |
| 261 | cieInfo->pointerEncoding = 0; | |
| 262 | cieInfo->lsdaEncoding = DW_EH_PE_omit; | |
| 263 | cieInfo->personalityEncoding = 0; | |
| 264 | cieInfo->personalityOffsetInCIE = 0; | |
| 265 | cieInfo->personality = 0; | |
| 266 | cieInfo->codeAlignFactor = 0; | |
| 267 | cieInfo->dataAlignFactor = 0; | |
| 268 | cieInfo->isSignalFrame = false; | |
| 269 | cieInfo->fdesHaveAugmentationData = false; | |
| 270 | #if defined(_LIBUNWIND_TARGET_AARCH64) | |
| 271 | cieInfo->addressesSignedWithBKey = false; | |
| 272 | #endif | |
| 273 | cieInfo->cieStart = cie; | |
| 274 | pint_t p = cie; | |
| 275 | pint_t cieLength = (pint_t)addressSpace.get32(p); | |
| 276 | p += 4; | |
| 277 | pint_t cieContentEnd = p + cieLength; | |
| 278 | if (cieLength == 0xffffffff) { | |
| 279 | // 0xffffffff means length is really next 8 bytes | |
| 280 | cieLength = (pint_t)addressSpace.get64(p); | |
| 281 | p += 8; | |
| 282 | cieContentEnd = p + cieLength; | |
| 283 | } | |
| 284 | if (cieLength == 0) | |
| 285 | return NULL; | |
| 286 | // CIE ID is always 0 | |
| 287 | if (addressSpace.get32(p) != 0) | |
| 288 | return "CIE ID is not zero"; | |
| 289 | p += 4; | |
| 290 | // Version is always 1 or 3 | |
| 291 | uint8_t version = addressSpace.get8(p); | |
| 292 | if ((version != 1) && (version != 3)) | |
| 293 | return "CIE version is not 1 or 3"; | |
| 294 | ++p; | |
| 295 | // save start of augmentation string and find end | |
| 296 | pint_t strStart = p; | |
| 297 | while (addressSpace.get8(p) != 0) | |
| 298 | ++p; | |
| 299 | ++p; | |
| 300 | // parse code aligment factor | |
| 301 | cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd); | |
| 302 | // parse data alignment factor | |
| 303 | cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd); | |
| 304 | // parse return address register | |
| 305 | uint64_t raReg = addressSpace.getULEB128(p, cieContentEnd); | |
| 306 | assert(raReg < 255 && "return address register too large"); | |
| 307 | cieInfo->returnAddressRegister = (uint8_t)raReg; | |
| 308 | // parse augmentation data based on augmentation string | |
| 309 | const char *result = NULL; | |
| 310 | if (addressSpace.get8(strStart) == 'z') { | |
| 311 | // parse augmentation data length | |
| 312 | addressSpace.getULEB128(p, cieContentEnd); | |
| 313 | for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) { | |
| 314 | switch (addressSpace.get8(s)) { | |
| 315 | case 'z': | |
| 316 | cieInfo->fdesHaveAugmentationData = true; | |
| 317 | break; | |
| 318 | case 'P': | |
| 319 | cieInfo->personalityEncoding = addressSpace.get8(p); | |
| 320 | ++p; | |
| 321 | cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie); | |
| 322 | cieInfo->personality = addressSpace | |
| 323 | .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding); | |
| 324 | break; | |
| 325 | case 'L': | |
| 326 | cieInfo->lsdaEncoding = addressSpace.get8(p); | |
| 327 | ++p; | |
| 328 | break; | |
| 329 | case 'R': | |
| 330 | cieInfo->pointerEncoding = addressSpace.get8(p); | |
| 331 | ++p; | |
| 332 | break; | |
| 333 | case 'S': | |
| 334 | cieInfo->isSignalFrame = true; | |
| 335 | break; | |
| 336 | #if defined(_LIBUNWIND_TARGET_AARCH64) | |
| 337 | case 'B': | |
| 338 | cieInfo->addressesSignedWithBKey = true; | |
| 339 | break; | |
| 340 | #endif | |
| 341 | default: | |
| 342 | // ignore unknown letters | |
| 343 | break; | |
| 344 | } | |
| 345 | } | |
| 346 | } | |
| 347 | cieInfo->cieLength = cieContentEnd - cieInfo->cieStart; | |
| 348 | cieInfo->cieInstructions = p; | |
| 349 | return result; | |
| 350 | } | |
| 351 | ||
| 352 | ||
| 353 | /// "run" the DWARF instructions and create the abstact PrologInfo for an FDE | |
| 354 | template <typename A> | |
| 355 | bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace, | |
| 356 | const FDE_Info &fdeInfo, | |
| 357 | const CIE_Info &cieInfo, pint_t upToPC, | |
| 358 | int arch, PrologInfo *results) { | |
| 359 | // clear results | |
| 360 | memset(results, '\0', sizeof(PrologInfo)); | |
| 361 | PrologInfoStackEntry *rememberStack = NULL; | |
| 362 | ||
| 363 | // parse CIE then FDE instructions | |
| 364 | return parseInstructions(addressSpace, cieInfo.cieInstructions, | |
| 365 | cieInfo.cieStart + cieInfo.cieLength, cieInfo, | |
| 366 | (pint_t)(-1), rememberStack, arch, results) && | |
| 367 | parseInstructions(addressSpace, fdeInfo.fdeInstructions, | |
| 368 | fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo, | |
| 369 | upToPC - fdeInfo.pcStart, rememberStack, arch, | |
| 370 | results); | |
| 371 | } | |
| 372 | ||
| 373 | /// "run" the DWARF instructions | |
| 374 | template <typename A> | |
| 375 | bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions, | |
| 376 | pint_t instructionsEnd, | |
| 377 | const CIE_Info &cieInfo, pint_t pcoffset, | |
| 378 | PrologInfoStackEntry *&rememberStack, | |
| 379 | int arch, PrologInfo *results) { | |
| 380 | pint_t p = instructions; | |
| 381 | pint_t codeOffset = 0; | |
| 382 | PrologInfo initialState = *results; | |
| 383 | ||
| 384 | _LIBUNWIND_TRACE_DWARF("parseInstructions(instructions=0x%0" PRIx64 ")\n", | |
| 385 | static_cast<uint64_t>(instructionsEnd)); | |
| 386 | ||
| 387 | // see DWARF Spec, section 6.4.2 for details on unwind opcodes | |
| 388 | while ((p < instructionsEnd) && (codeOffset < pcoffset)) { | |
| 389 | uint64_t reg; | |
| 390 | uint64_t reg2; | |
| 391 | int64_t offset; | |
| 392 | uint64_t length; | |
| 393 | uint8_t opcode = addressSpace.get8(p); | |
| 394 | uint8_t operand; | |
| 395 | #if !defined(_LIBUNWIND_NO_HEAP) | |
| 396 | PrologInfoStackEntry *entry; | |
| 397 | #endif | |
| 398 | ++p; | |
| 399 | switch (opcode) { | |
| 400 | case DW_CFA_nop: | |
| 401 | _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n"); | |
| 402 | break; | |
| 403 | case DW_CFA_set_loc: | |
| 404 | codeOffset = | |
| 405 | addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding); | |
| 406 | _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n"); | |
| 407 | break; | |
| 408 | case DW_CFA_advance_loc1: | |
| 409 | codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor); | |
| 410 | p += 1; | |
| 411 | _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n", | |
| 412 | static_cast<uint64_t>(codeOffset)); | |
| 413 | break; | |
| 414 | case DW_CFA_advance_loc2: | |
| 415 | codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor); | |
| 416 | p += 2; | |
| 417 | _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n", | |
| 418 | static_cast<uint64_t>(codeOffset)); | |
| 419 | break; | |
| 420 | case DW_CFA_advance_loc4: | |
| 421 | codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor); | |
| 422 | p += 4; | |
| 423 | _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n", | |
| 424 | static_cast<uint64_t>(codeOffset)); | |
| 425 | break; | |
| 426 | case DW_CFA_offset_extended: | |
| 427 | reg = addressSpace.getULEB128(p, instructionsEnd); | |
| 428 | offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) | |
| 429 | * cieInfo.dataAlignFactor; | |
| 430 | if (reg > kMaxRegisterNumber) { | |
| 431 | _LIBUNWIND_LOG0( | |
| 432 | "malformed DW_CFA_offset_extended DWARF unwind, reg too big"); | |
| 433 | return false; | |
| 434 | } | |
| 435 | results->savedRegisters[reg].location = kRegisterInCFA; | |
| 436 | results->savedRegisters[reg].value = offset; | |
| 437 | _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", " | |
| 438 | "offset=%" PRId64 ")\n", | |
| 439 | reg, offset); | |
| 440 | break; | |
| 441 | case DW_CFA_restore_extended: | |
| 442 | reg = addressSpace.getULEB128(p, instructionsEnd); | |
| 443 | if (reg > kMaxRegisterNumber) { | |
| 444 | _LIBUNWIND_LOG0( | |
| 445 | "malformed DW_CFA_restore_extended DWARF unwind, reg too big"); | |
| 446 | return false; | |
| 447 | } | |
| 448 | results->savedRegisters[reg] = initialState.savedRegisters[reg]; | |
| 449 | _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg); | |
| 450 | break; | |
| 451 | case DW_CFA_undefined: | |
| 452 | reg = addressSpace.getULEB128(p, instructionsEnd); | |
| 453 | if (reg > kMaxRegisterNumber) { | |
| 454 | _LIBUNWIND_LOG0( | |
| 455 | "malformed DW_CFA_undefined DWARF unwind, reg too big"); | |
| 456 | return false; | |
| 457 | } | |
| 458 | results->savedRegisters[reg].location = kRegisterUnused; | |
| 459 | _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg); | |
| 460 | break; | |
| 461 | case DW_CFA_same_value: | |
| 462 | reg = addressSpace.getULEB128(p, instructionsEnd); | |
| 463 | if (reg > kMaxRegisterNumber) { | |
| 464 | _LIBUNWIND_LOG0( | |
| 465 | "malformed DW_CFA_same_value DWARF unwind, reg too big"); | |
| 466 | return false; | |
| 467 | } | |
| 468 | // <rdar://problem/8456377> DW_CFA_same_value unsupported | |
| 469 | // "same value" means register was stored in frame, but its current | |
| 470 | // value has not changed, so no need to restore from frame. | |
| 471 | // We model this as if the register was never saved. | |
| 472 | results->savedRegisters[reg].location = kRegisterUnused; | |
| 473 | // set flag to disable conversion to compact unwind | |
| 474 | results->sameValueUsed = true; | |
| 475 | _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg); | |
| 476 | break; | |
| 477 | case DW_CFA_register: | |
| 478 | reg = addressSpace.getULEB128(p, instructionsEnd); | |
| 479 | reg2 = addressSpace.getULEB128(p, instructionsEnd); | |
| 480 | if (reg > kMaxRegisterNumber) { | |
| 481 | _LIBUNWIND_LOG0( | |
| 482 | "malformed DW_CFA_register DWARF unwind, reg too big"); | |
| 483 | return false; | |
| 484 | } | |
| 485 | if (reg2 > kMaxRegisterNumber) { | |
| 486 | _LIBUNWIND_LOG0( | |
| 487 | "malformed DW_CFA_register DWARF unwind, reg2 too big"); | |
| 488 | return false; | |
| 489 | } | |
| 490 | results->savedRegisters[reg].location = kRegisterInRegister; | |
| 491 | results->savedRegisters[reg].value = (int64_t)reg2; | |
| 492 | // set flag to disable conversion to compact unwind | |
| 493 | results->registersInOtherRegisters = true; | |
| 494 | _LIBUNWIND_TRACE_DWARF( | |
| 495 | "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2); | |
| 496 | break; | |
| 497 | #if !defined(_LIBUNWIND_NO_HEAP) | |
| 498 | case DW_CFA_remember_state: | |
| 499 | // avoid operator new, because that would be an upward dependency | |
| 500 | entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry)); | |
| 501 | if (entry != NULL) { | |
| 502 | entry->next = rememberStack; | |
| 503 | entry->info = *results; | |
| 504 | rememberStack = entry; | |
| 505 | } else { | |
| 506 | return false; | |
| 507 | } | |
| 508 | _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n"); | |
| 509 | break; | |
| 510 | case DW_CFA_restore_state: | |
| 511 | if (rememberStack != NULL) { | |
| 512 | PrologInfoStackEntry *top = rememberStack; | |
| 513 | *results = top->info; | |
| 514 | rememberStack = top->next; | |
| 515 | free((char *)top); | |
| 516 | } else { | |
| 517 | return false; | |
| 518 | } | |
| 519 | _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n"); | |
| 520 | break; | |
| 521 | #endif | |
| 522 | case DW_CFA_def_cfa: | |
| 523 | reg = addressSpace.getULEB128(p, instructionsEnd); | |
| 524 | offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd); | |
| 525 | if (reg > kMaxRegisterNumber) { | |
| 526 | _LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big"); | |
| 527 | return false; | |
| 528 | } | |
| 529 | results->cfaRegister = (uint32_t)reg; | |
| 530 | results->cfaRegisterOffset = (int32_t)offset; | |
| 531 | _LIBUNWIND_TRACE_DWARF( | |
| 532 | "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", reg, offset); | |
| 533 | break; | |
| 534 | case DW_CFA_def_cfa_register: | |
| 535 | reg = addressSpace.getULEB128(p, instructionsEnd); | |
| 536 | if (reg > kMaxRegisterNumber) { | |
| 537 | _LIBUNWIND_LOG0( | |
| 538 | "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big"); | |
| 539 | return false; | |
| 540 | } | |
| 541 | results->cfaRegister = (uint32_t)reg; | |
| 542 | _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg); | |
| 543 | break; | |
| 544 | case DW_CFA_def_cfa_offset: | |
| 545 | results->cfaRegisterOffset = (int32_t) | |
| 546 | addressSpace.getULEB128(p, instructionsEnd); | |
| 547 | results->codeOffsetAtStackDecrement = (uint32_t)codeOffset; | |
| 548 | _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n", | |
| 549 | results->cfaRegisterOffset); | |
| 550 | break; | |
| 551 | case DW_CFA_def_cfa_expression: | |
| 552 | results->cfaRegister = 0; | |
| 553 | results->cfaExpression = (int64_t)p; | |
| 554 | length = addressSpace.getULEB128(p, instructionsEnd); | |
| 555 | assert(length < static_cast<pint_t>(~0) && "pointer overflow"); | |
| 556 | p += static_cast<pint_t>(length); | |
| 557 | _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64 | |
| 558 | ", length=%" PRIu64 ")\n", | |
| 559 | results->cfaExpression, length); | |
| 560 | break; | |
| 561 | case DW_CFA_expression: | |
| 562 | reg = addressSpace.getULEB128(p, instructionsEnd); | |
| 563 | if (reg > kMaxRegisterNumber) { | |
| 564 | _LIBUNWIND_LOG0( | |
| 565 | "malformed DW_CFA_expression DWARF unwind, reg too big"); | |
| 566 | return false; | |
| 567 | } | |
| 568 | results->savedRegisters[reg].location = kRegisterAtExpression; | |
| 569 | results->savedRegisters[reg].value = (int64_t)p; | |
| 570 | length = addressSpace.getULEB128(p, instructionsEnd); | |
| 571 | assert(length < static_cast<pint_t>(~0) && "pointer overflow"); | |
| 572 | p += static_cast<pint_t>(length); | |
| 573 | _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", " | |
| 574 | "expression=0x%" PRIx64 ", " | |
| 575 | "length=%" PRIu64 ")\n", | |
| 576 | reg, results->savedRegisters[reg].value, length); | |
| 577 | break; | |
| 578 | case DW_CFA_offset_extended_sf: | |
| 579 | reg = addressSpace.getULEB128(p, instructionsEnd); | |
| 580 | if (reg > kMaxRegisterNumber) { | |
| 581 | _LIBUNWIND_LOG0( | |
| 582 | "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big"); | |
| 583 | return false; | |
| 584 | } | |
| 585 | offset = | |
| 586 | addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; | |
| 587 | results->savedRegisters[reg].location = kRegisterInCFA; | |
| 588 | results->savedRegisters[reg].value = offset; | |
| 589 | _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", " | |
| 590 | "offset=%" PRId64 ")\n", | |
| 591 | reg, offset); | |
| 592 | break; | |
| 593 | case DW_CFA_def_cfa_sf: | |
| 594 | reg = addressSpace.getULEB128(p, instructionsEnd); | |
| 595 | offset = | |
| 596 | addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; | |
| 597 | if (reg > kMaxRegisterNumber) { | |
| 598 | _LIBUNWIND_LOG0( | |
| 599 | "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big"); | |
| 600 | return false; | |
| 601 | } | |
| 602 | results->cfaRegister = (uint32_t)reg; | |
| 603 | results->cfaRegisterOffset = (int32_t)offset; | |
| 604 | _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", " | |
| 605 | "offset=%" PRId64 ")\n", | |
| 606 | reg, offset); | |
| 607 | break; | |
| 608 | case DW_CFA_def_cfa_offset_sf: | |
| 609 | results->cfaRegisterOffset = (int32_t) | |
| 610 | (addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor); | |
| 611 | results->codeOffsetAtStackDecrement = (uint32_t)codeOffset; | |
| 612 | _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n", | |
| 613 | results->cfaRegisterOffset); | |
| 614 | break; | |
| 615 | case DW_CFA_val_offset: | |
| 616 | reg = addressSpace.getULEB128(p, instructionsEnd); | |
| 617 | if (reg > kMaxRegisterNumber) { | |
| 618 | _LIBUNWIND_LOG( | |
| 619 | "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64 | |
| 620 | ") out of range\n", | |
| 621 | reg); | |
| 622 | return false; | |
| 623 | } | |
| 624 | offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) | |
| 625 | * cieInfo.dataAlignFactor; | |
| 626 | results->savedRegisters[reg].location = kRegisterOffsetFromCFA; | |
| 627 | results->savedRegisters[reg].value = offset; | |
| 628 | _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", " | |
| 629 | "offset=%" PRId64 "\n", | |
| 630 | reg, offset); | |
| 631 | break; | |
| 632 | case DW_CFA_val_offset_sf: | |
| 633 | reg = addressSpace.getULEB128(p, instructionsEnd); | |
| 634 | if (reg > kMaxRegisterNumber) { | |
| 635 | _LIBUNWIND_LOG0( | |
| 636 | "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big"); | |
| 637 | return false; | |
| 638 | } | |
| 639 | offset = | |
| 640 | addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; | |
| 641 | results->savedRegisters[reg].location = kRegisterOffsetFromCFA; | |
| 642 | results->savedRegisters[reg].value = offset; | |
| 643 | _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", " | |
| 644 | "offset=%" PRId64 "\n", | |
| 645 | reg, offset); | |
| 646 | break; | |
| 647 | case DW_CFA_val_expression: | |
| 648 | reg = addressSpace.getULEB128(p, instructionsEnd); | |
| 649 | if (reg > kMaxRegisterNumber) { | |
| 650 | _LIBUNWIND_LOG0( | |
| 651 | "malformed DW_CFA_val_expression DWARF unwind, reg too big"); | |
| 652 | return false; | |
| 653 | } | |
| 654 | results->savedRegisters[reg].location = kRegisterIsExpression; | |
| 655 | results->savedRegisters[reg].value = (int64_t)p; | |
| 656 | length = addressSpace.getULEB128(p, instructionsEnd); | |
| 657 | assert(length < static_cast<pint_t>(~0) && "pointer overflow"); | |
| 658 | p += static_cast<pint_t>(length); | |
| 659 | _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", " | |
| 660 | "expression=0x%" PRIx64 ", length=%" PRIu64 ")\n", | |
| 661 | reg, results->savedRegisters[reg].value, length); | |
| 662 | break; | |
| 663 | case DW_CFA_GNU_args_size: | |
| 664 | length = addressSpace.getULEB128(p, instructionsEnd); | |
| 665 | results->spExtraArgSize = (uint32_t)length; | |
| 666 | _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length); | |
| 667 | break; | |
| 668 | case DW_CFA_GNU_negative_offset_extended: | |
| 669 | reg = addressSpace.getULEB128(p, instructionsEnd); | |
| 670 | if (reg > kMaxRegisterNumber) { | |
| 671 | _LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF " | |
| 672 | "unwind, reg too big"); | |
| 673 | return false; | |
| 674 | } | |
| 675 | offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) | |
| 676 | * cieInfo.dataAlignFactor; | |
| 677 | results->savedRegisters[reg].location = kRegisterInCFA; | |
| 678 | results->savedRegisters[reg].value = -offset; | |
| 679 | _LIBUNWIND_TRACE_DWARF( | |
| 680 | "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset); | |
| 681 | break; | |
| 682 | ||
| 683 | #if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC) | |
| 684 | // The same constant is used to represent different instructions on | |
| 685 | // AArch64 (negate_ra_state) and SPARC (window_save). | |
| 686 | static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save, | |
| 687 | "uses the same constant"); | |
| 688 | case DW_CFA_AARCH64_negate_ra_state: | |
| 689 | switch (arch) { | |
| 690 | #if defined(_LIBUNWIND_TARGET_AARCH64) | |
| 691 | case REGISTERS_ARM64: | |
| 692 | results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^= 0x1; | |
| 693 | _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n"); | |
| 694 | break; | |
| 695 | #endif | |
| 696 | #if defined(_LIBUNWIND_TARGET_SPARC) | |
| 697 | // case DW_CFA_GNU_window_save: | |
| 698 | case REGISTERS_SPARC: | |
| 699 | _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n"); | |
| 700 | for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) { | |
| 701 | results->savedRegisters[reg].location = kRegisterInRegister; | |
| 702 | results->savedRegisters[reg].value = | |
| 703 | ((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0; | |
| 704 | } | |
| 705 | ||
| 706 | for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) { | |
| 707 | results->savedRegisters[reg].location = kRegisterInCFA; | |
| 708 | results->savedRegisters[reg].value = | |
| 709 | ((int64_t)reg - UNW_SPARC_L0) * 4; | |
| 710 | } | |
| 711 | break; | |
| 712 | #endif | |
| 713 | } | |
| 714 | break; | |
| 715 | #else | |
| 716 | (void)arch; | |
| 717 | #endif | |
| 718 | ||
| 719 | default: | |
| 720 | operand = opcode & 0x3F; | |
| 721 | switch (opcode & 0xC0) { | |
| 722 | case DW_CFA_offset: | |
| 723 | reg = operand; | |
| 724 | if (reg > kMaxRegisterNumber) { | |
| 725 | _LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64 | |
| 726 | ") out of range", | |
| 727 | reg); | |
| 728 | return false; | |
| 729 | } | |
| 730 | offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) | |
| 731 | * cieInfo.dataAlignFactor; | |
| 732 | results->savedRegisters[reg].location = kRegisterInCFA; | |
| 733 | results->savedRegisters[reg].value = offset; | |
| 734 | _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n", | |
| 735 | operand, offset); | |
| 736 | break; | |
| 737 | case DW_CFA_advance_loc: | |
| 738 | codeOffset += operand * cieInfo.codeAlignFactor; | |
| 739 | _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n", | |
| 740 | static_cast<uint64_t>(codeOffset)); | |
| 741 | break; | |
| 742 | case DW_CFA_restore: | |
| 743 | reg = operand; | |
| 744 | if (reg > kMaxRegisterNumber) { | |
| 745 | _LIBUNWIND_LOG("malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64 | |
| 746 | ") out of range", | |
| 747 | reg); | |
| 748 | return false; | |
| 749 | } | |
| 750 | results->savedRegisters[reg] = initialState.savedRegisters[reg]; | |
| 751 | _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n", | |
| 752 | static_cast<uint64_t>(operand)); | |
| 753 | break; | |
| 754 | default: | |
| 755 | _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode); | |
| 756 | return false; | |
| 757 | } | |
| 758 | } | |
| 759 | } | |
| 760 | ||
| 761 | return true; | |
| 762 | } | |
| 763 | ||
| 764 | } // namespace libunwind | |
| 765 | ||
| 766 | #endif // __DWARF_PARSER_HPP__ |
libunwind/src/EHHeaderParser.hpp created+168| ... | ... | @@ -0,0 +1,168 @@ |
| 1 | //===------------------------- EHHeaderParser.hpp -------------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is dual licensed under the MIT and the University of Illinois Open | |
| 6 | // Source Licenses. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | // | |
| 9 | // Parses ELF .eh_frame_hdr sections. | |
| 10 | // | |
| 11 | //===----------------------------------------------------------------------===// | |
| 12 | ||
| 13 | #ifndef __EHHEADERPARSER_HPP__ | |
| 14 | #define __EHHEADERPARSER_HPP__ | |
| 15 | ||
| 16 | #include "libunwind.h" | |
| 17 | ||
| 18 | #include "DwarfParser.hpp" | |
| 19 | ||
| 20 | namespace libunwind { | |
| 21 | ||
| 22 | /// \brief EHHeaderParser does basic parsing of an ELF .eh_frame_hdr section. | |
| 23 | /// | |
| 24 | /// See DWARF spec for details: | |
| 25 | /// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html | |
| 26 | /// | |
| 27 | template <typename A> class EHHeaderParser { | |
| 28 | public: | |
| 29 | typedef typename A::pint_t pint_t; | |
| 30 | ||
| 31 | /// Information encoded in the EH frame header. | |
| 32 | struct EHHeaderInfo { | |
| 33 | pint_t eh_frame_ptr; | |
| 34 | size_t fde_count; | |
| 35 | pint_t table; | |
| 36 | uint8_t table_enc; | |
| 37 | }; | |
| 38 | ||
| 39 | static bool decodeEHHdr(A &addressSpace, pint_t ehHdrStart, pint_t ehHdrEnd, | |
| 40 | EHHeaderInfo &ehHdrInfo); | |
| 41 | static bool findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart, | |
| 42 | uint32_t sectionLength, | |
| 43 | typename CFI_Parser<A>::FDE_Info *fdeInfo, | |
| 44 | typename CFI_Parser<A>::CIE_Info *cieInfo); | |
| 45 | ||
| 46 | private: | |
| 47 | static bool decodeTableEntry(A &addressSpace, pint_t &tableEntry, | |
| 48 | pint_t ehHdrStart, pint_t ehHdrEnd, | |
| 49 | uint8_t tableEnc, | |
| 50 | typename CFI_Parser<A>::FDE_Info *fdeInfo, | |
| 51 | typename CFI_Parser<A>::CIE_Info *cieInfo); | |
| 52 | static size_t getTableEntrySize(uint8_t tableEnc); | |
| 53 | }; | |
| 54 | ||
| 55 | template <typename A> | |
| 56 | bool EHHeaderParser<A>::decodeEHHdr(A &addressSpace, pint_t ehHdrStart, | |
| 57 | pint_t ehHdrEnd, EHHeaderInfo &ehHdrInfo) { | |
| 58 | pint_t p = ehHdrStart; | |
| 59 | uint8_t version = addressSpace.get8(p++); | |
| 60 | if (version != 1) { | |
| 61 | _LIBUNWIND_LOG0("Unsupported .eh_frame_hdr version"); | |
| 62 | return false; | |
| 63 | } | |
| 64 | ||
| 65 | uint8_t eh_frame_ptr_enc = addressSpace.get8(p++); | |
| 66 | uint8_t fde_count_enc = addressSpace.get8(p++); | |
| 67 | ehHdrInfo.table_enc = addressSpace.get8(p++); | |
| 68 | ||
| 69 | ehHdrInfo.eh_frame_ptr = | |
| 70 | addressSpace.getEncodedP(p, ehHdrEnd, eh_frame_ptr_enc, ehHdrStart); | |
| 71 | ehHdrInfo.fde_count = | |
| 72 | fde_count_enc == DW_EH_PE_omit | |
| 73 | ? 0 | |
| 74 | : addressSpace.getEncodedP(p, ehHdrEnd, fde_count_enc, ehHdrStart); | |
| 75 | ehHdrInfo.table = p; | |
| 76 | ||
| 77 | return true; | |
| 78 | } | |
| 79 | ||
| 80 | template <typename A> | |
| 81 | bool EHHeaderParser<A>::decodeTableEntry( | |
| 82 | A &addressSpace, pint_t &tableEntry, pint_t ehHdrStart, pint_t ehHdrEnd, | |
| 83 | uint8_t tableEnc, typename CFI_Parser<A>::FDE_Info *fdeInfo, | |
| 84 | typename CFI_Parser<A>::CIE_Info *cieInfo) { | |
| 85 | // Have to decode the whole FDE for the PC range anyway, so just throw away | |
| 86 | // the PC start. | |
| 87 | addressSpace.getEncodedP(tableEntry, ehHdrEnd, tableEnc, ehHdrStart); | |
| 88 | pint_t fde = | |
| 89 | addressSpace.getEncodedP(tableEntry, ehHdrEnd, tableEnc, ehHdrStart); | |
| 90 | const char *message = | |
| 91 | CFI_Parser<A>::decodeFDE(addressSpace, fde, fdeInfo, cieInfo); | |
| 92 | if (message != NULL) { | |
| 93 | _LIBUNWIND_DEBUG_LOG("EHHeaderParser::decodeTableEntry: bad fde: %s", | |
| 94 | message); | |
| 95 | return false; | |
| 96 | } | |
| 97 | ||
| 98 | return true; | |
| 99 | } | |
| 100 | ||
| 101 | template <typename A> | |
| 102 | bool EHHeaderParser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart, | |
| 103 | uint32_t sectionLength, | |
| 104 | typename CFI_Parser<A>::FDE_Info *fdeInfo, | |
| 105 | typename CFI_Parser<A>::CIE_Info *cieInfo) { | |
| 106 | pint_t ehHdrEnd = ehHdrStart + sectionLength; | |
| 107 | ||
| 108 | EHHeaderParser<A>::EHHeaderInfo hdrInfo; | |
| 109 | if (!EHHeaderParser<A>::decodeEHHdr(addressSpace, ehHdrStart, ehHdrEnd, | |
| 110 | hdrInfo)) | |
| 111 | return false; | |
| 112 | ||
| 113 | size_t tableEntrySize = getTableEntrySize(hdrInfo.table_enc); | |
| 114 | pint_t tableEntry; | |
| 115 | ||
| 116 | size_t low = 0; | |
| 117 | for (size_t len = hdrInfo.fde_count; len > 1;) { | |
| 118 | size_t mid = low + (len / 2); | |
| 119 | tableEntry = hdrInfo.table + mid * tableEntrySize; | |
| 120 | pint_t start = addressSpace.getEncodedP(tableEntry, ehHdrEnd, | |
| 121 | hdrInfo.table_enc, ehHdrStart); | |
| 122 | ||
| 123 | if (start == pc) { | |
| 124 | low = mid; | |
| 125 | break; | |
| 126 | } else if (start < pc) { | |
| 127 | low = mid; | |
| 128 | len -= (len / 2); | |
| 129 | } else { | |
| 130 | len /= 2; | |
| 131 | } | |
| 132 | } | |
| 133 | ||
| 134 | tableEntry = hdrInfo.table + low * tableEntrySize; | |
| 135 | if (decodeTableEntry(addressSpace, tableEntry, ehHdrStart, ehHdrEnd, | |
| 136 | hdrInfo.table_enc, fdeInfo, cieInfo)) { | |
| 137 | if (pc >= fdeInfo->pcStart && pc < fdeInfo->pcEnd) | |
| 138 | return true; | |
| 139 | } | |
| 140 | ||
| 141 | return false; | |
| 142 | } | |
| 143 | ||
| 144 | template <typename A> | |
| 145 | size_t EHHeaderParser<A>::getTableEntrySize(uint8_t tableEnc) { | |
| 146 | switch (tableEnc & 0x0f) { | |
| 147 | case DW_EH_PE_sdata2: | |
| 148 | case DW_EH_PE_udata2: | |
| 149 | return 4; | |
| 150 | case DW_EH_PE_sdata4: | |
| 151 | case DW_EH_PE_udata4: | |
| 152 | return 8; | |
| 153 | case DW_EH_PE_sdata8: | |
| 154 | case DW_EH_PE_udata8: | |
| 155 | return 16; | |
| 156 | case DW_EH_PE_sleb128: | |
| 157 | case DW_EH_PE_uleb128: | |
| 158 | _LIBUNWIND_ABORT("Can't binary search on variable length encoded data."); | |
| 159 | case DW_EH_PE_omit: | |
| 160 | return 0; | |
| 161 | default: | |
| 162 | _LIBUNWIND_ABORT("Unknown DWARF encoding for search table."); | |
| 163 | } | |
| 164 | } | |
| 165 | ||
| 166 | } | |
| 167 | ||
| 168 | #endif |
libunwind/src/RWMutex.hpp created+77| ... | ... | @@ -0,0 +1,77 @@ |
| 1 | //===----------------------------- Registers.hpp --------------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is dual licensed under the MIT and the University of Illinois Open | |
| 6 | // Source Licenses. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | // | |
| 9 | // Abstract interface to shared reader/writer log, hiding platform and | |
| 10 | // configuration differences. | |
| 11 | // | |
| 12 | //===----------------------------------------------------------------------===// | |
| 13 | ||
| 14 | #ifndef __RWMUTEX_HPP__ | |
| 15 | #define __RWMUTEX_HPP__ | |
| 16 | ||
| 17 | #if defined(_WIN32) | |
| 18 | #include <windows.h> | |
| 19 | #elif !defined(_LIBUNWIND_HAS_NO_THREADS) | |
| 20 | #include <pthread.h> | |
| 21 | #endif | |
| 22 | ||
| 23 | namespace libunwind { | |
| 24 | ||
| 25 | #if defined(_LIBUNWIND_HAS_NO_THREADS) | |
| 26 | ||
| 27 | class _LIBUNWIND_HIDDEN RWMutex { | |
| 28 | public: | |
| 29 | bool lock_shared() { return true; } | |
| 30 | bool unlock_shared() { return true; } | |
| 31 | bool lock() { return true; } | |
| 32 | bool unlock() { return true; } | |
| 33 | }; | |
| 34 | ||
| 35 | #elif defined(_WIN32) | |
| 36 | ||
| 37 | class _LIBUNWIND_HIDDEN RWMutex { | |
| 38 | public: | |
| 39 | bool lock_shared() { | |
| 40 | AcquireSRWLockShared(&_lock); | |
| 41 | return true; | |
| 42 | } | |
| 43 | bool unlock_shared() { | |
| 44 | ReleaseSRWLockShared(&_lock); | |
| 45 | return true; | |
| 46 | } | |
| 47 | bool lock() { | |
| 48 | AcquireSRWLockExclusive(&_lock); | |
| 49 | return true; | |
| 50 | } | |
| 51 | bool unlock() { | |
| 52 | ReleaseSRWLockExclusive(&_lock); | |
| 53 | return true; | |
| 54 | } | |
| 55 | ||
| 56 | private: | |
| 57 | SRWLOCK _lock = SRWLOCK_INIT; | |
| 58 | }; | |
| 59 | ||
| 60 | #else | |
| 61 | ||
| 62 | class _LIBUNWIND_HIDDEN RWMutex { | |
| 63 | public: | |
| 64 | bool lock_shared() { return pthread_rwlock_rdlock(&_lock) == 0; } | |
| 65 | bool unlock_shared() { return pthread_rwlock_unlock(&_lock) == 0; } | |
| 66 | bool lock() { return pthread_rwlock_wrlock(&_lock) == 0; } | |
| 67 | bool unlock() { return pthread_rwlock_unlock(&_lock) == 0; } | |
| 68 | ||
| 69 | private: | |
| 70 | pthread_rwlock_t _lock = PTHREAD_RWLOCK_INITIALIZER; | |
| 71 | }; | |
| 72 | ||
| 73 | #endif | |
| 74 | ||
| 75 | } // namespace libunwind | |
| 76 | ||
| 77 | #endif // __RWMUTEX_HPP__ |
libunwind/src/Registers.hpp created+3523| ... | ... | @@ -0,0 +1,3523 @@ |
| 1 | //===----------------------------- Registers.hpp --------------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is dual licensed under the MIT and the University of Illinois Open | |
| 6 | // Source Licenses. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | // | |
| 9 | // Models register sets for supported processors. | |
| 10 | // | |
| 11 | //===----------------------------------------------------------------------===// | |
| 12 | ||
| 13 | #ifndef __REGISTERS_HPP__ | |
| 14 | #define __REGISTERS_HPP__ | |
| 15 | ||
| 16 | #include <stdint.h> | |
| 17 | #include <string.h> | |
| 18 | ||
| 19 | #include "libunwind.h" | |
| 20 | #include "config.h" | |
| 21 | ||
| 22 | namespace libunwind { | |
| 23 | ||
| 24 | // For emulating 128-bit registers | |
| 25 | struct v128 { uint32_t vec[4]; }; | |
| 26 | ||
| 27 | enum { | |
| 28 | REGISTERS_X86, | |
| 29 | REGISTERS_X86_64, | |
| 30 | REGISTERS_PPC, | |
| 31 | REGISTERS_PPC64, | |
| 32 | REGISTERS_ARM64, | |
| 33 | REGISTERS_ARM, | |
| 34 | REGISTERS_OR1K, | |
| 35 | REGISTERS_MIPS_O32, | |
| 36 | REGISTERS_MIPS_NEWABI, | |
| 37 | REGISTERS_SPARC, | |
| 38 | }; | |
| 39 | ||
| 40 | #if defined(_LIBUNWIND_TARGET_I386) | |
| 41 | /// Registers_x86 holds the register state of a thread in a 32-bit intel | |
| 42 | /// process. | |
| 43 | class _LIBUNWIND_HIDDEN Registers_x86 { | |
| 44 | public: | |
| 45 | Registers_x86(); | |
| 46 | Registers_x86(const void *registers); | |
| 47 | ||
| 48 | bool validRegister(int num) const; | |
| 49 | uint32_t getRegister(int num) const; | |
| 50 | void setRegister(int num, uint32_t value); | |
| 51 | bool validFloatRegister(int) const { return false; } | |
| 52 | double getFloatRegister(int num) const; | |
| 53 | void setFloatRegister(int num, double value); | |
| 54 | bool validVectorRegister(int) const { return false; } | |
| 55 | v128 getVectorRegister(int num) const; | |
| 56 | void setVectorRegister(int num, v128 value); | |
| 57 | static const char *getRegisterName(int num); | |
| 58 | void jumpto(); | |
| 59 | static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86; } | |
| 60 | static int getArch() { return REGISTERS_X86; } | |
| 61 | ||
| 62 | uint32_t getSP() const { return _registers.__esp; } | |
| 63 | void setSP(uint32_t value) { _registers.__esp = value; } | |
| 64 | uint32_t getIP() const { return _registers.__eip; } | |
| 65 | void setIP(uint32_t value) { _registers.__eip = value; } | |
| 66 | uint32_t getEBP() const { return _registers.__ebp; } | |
| 67 | void setEBP(uint32_t value) { _registers.__ebp = value; } | |
| 68 | uint32_t getEBX() const { return _registers.__ebx; } | |
| 69 | void setEBX(uint32_t value) { _registers.__ebx = value; } | |
| 70 | uint32_t getECX() const { return _registers.__ecx; } | |
| 71 | void setECX(uint32_t value) { _registers.__ecx = value; } | |
| 72 | uint32_t getEDX() const { return _registers.__edx; } | |
| 73 | void setEDX(uint32_t value) { _registers.__edx = value; } | |
| 74 | uint32_t getESI() const { return _registers.__esi; } | |
| 75 | void setESI(uint32_t value) { _registers.__esi = value; } | |
| 76 | uint32_t getEDI() const { return _registers.__edi; } | |
| 77 | void setEDI(uint32_t value) { _registers.__edi = value; } | |
| 78 | ||
| 79 | private: | |
| 80 | struct GPRs { | |
| 81 | unsigned int __eax; | |
| 82 | unsigned int __ebx; | |
| 83 | unsigned int __ecx; | |
| 84 | unsigned int __edx; | |
| 85 | unsigned int __edi; | |
| 86 | unsigned int __esi; | |
| 87 | unsigned int __ebp; | |
| 88 | unsigned int __esp; | |
| 89 | unsigned int __ss; | |
| 90 | unsigned int __eflags; | |
| 91 | unsigned int __eip; | |
| 92 | unsigned int __cs; | |
| 93 | unsigned int __ds; | |
| 94 | unsigned int __es; | |
| 95 | unsigned int __fs; | |
| 96 | unsigned int __gs; | |
| 97 | }; | |
| 98 | ||
| 99 | GPRs _registers; | |
| 100 | }; | |
| 101 | ||
| 102 | inline Registers_x86::Registers_x86(const void *registers) { | |
| 103 | static_assert((check_fit<Registers_x86, unw_context_t>::does_fit), | |
| 104 | "x86 registers do not fit into unw_context_t"); | |
| 105 | memcpy(&_registers, registers, sizeof(_registers)); | |
| 106 | } | |
| 107 | ||
| 108 | inline Registers_x86::Registers_x86() { | |
| 109 | memset(&_registers, 0, sizeof(_registers)); | |
| 110 | } | |
| 111 | ||
| 112 | inline bool Registers_x86::validRegister(int regNum) const { | |
| 113 | if (regNum == UNW_REG_IP) | |
| 114 | return true; | |
| 115 | if (regNum == UNW_REG_SP) | |
| 116 | return true; | |
| 117 | if (regNum < 0) | |
| 118 | return false; | |
| 119 | if (regNum > 7) | |
| 120 | return false; | |
| 121 | return true; | |
| 122 | } | |
| 123 | ||
| 124 | inline uint32_t Registers_x86::getRegister(int regNum) const { | |
| 125 | switch (regNum) { | |
| 126 | case UNW_REG_IP: | |
| 127 | return _registers.__eip; | |
| 128 | case UNW_REG_SP: | |
| 129 | return _registers.__esp; | |
| 130 | case UNW_X86_EAX: | |
| 131 | return _registers.__eax; | |
| 132 | case UNW_X86_ECX: | |
| 133 | return _registers.__ecx; | |
| 134 | case UNW_X86_EDX: | |
| 135 | return _registers.__edx; | |
| 136 | case UNW_X86_EBX: | |
| 137 | return _registers.__ebx; | |
| 138 | #if !defined(__APPLE__) | |
| 139 | case UNW_X86_ESP: | |
| 140 | #else | |
| 141 | case UNW_X86_EBP: | |
| 142 | #endif | |
| 143 | return _registers.__ebp; | |
| 144 | #if !defined(__APPLE__) | |
| 145 | case UNW_X86_EBP: | |
| 146 | #else | |
| 147 | case UNW_X86_ESP: | |
| 148 | #endif | |
| 149 | return _registers.__esp; | |
| 150 | case UNW_X86_ESI: | |
| 151 | return _registers.__esi; | |
| 152 | case UNW_X86_EDI: | |
| 153 | return _registers.__edi; | |
| 154 | } | |
| 155 | _LIBUNWIND_ABORT("unsupported x86 register"); | |
| 156 | } | |
| 157 | ||
| 158 | inline void Registers_x86::setRegister(int regNum, uint32_t value) { | |
| 159 | switch (regNum) { | |
| 160 | case UNW_REG_IP: | |
| 161 | _registers.__eip = value; | |
| 162 | return; | |
| 163 | case UNW_REG_SP: | |
| 164 | _registers.__esp = value; | |
| 165 | return; | |
| 166 | case UNW_X86_EAX: | |
| 167 | _registers.__eax = value; | |
| 168 | return; | |
| 169 | case UNW_X86_ECX: | |
| 170 | _registers.__ecx = value; | |
| 171 | return; | |
| 172 | case UNW_X86_EDX: | |
| 173 | _registers.__edx = value; | |
| 174 | return; | |
| 175 | case UNW_X86_EBX: | |
| 176 | _registers.__ebx = value; | |
| 177 | return; | |
| 178 | #if !defined(__APPLE__) | |
| 179 | case UNW_X86_ESP: | |
| 180 | #else | |
| 181 | case UNW_X86_EBP: | |
| 182 | #endif | |
| 183 | _registers.__ebp = value; | |
| 184 | return; | |
| 185 | #if !defined(__APPLE__) | |
| 186 | case UNW_X86_EBP: | |
| 187 | #else | |
| 188 | case UNW_X86_ESP: | |
| 189 | #endif | |
| 190 | _registers.__esp = value; | |
| 191 | return; | |
| 192 | case UNW_X86_ESI: | |
| 193 | _registers.__esi = value; | |
| 194 | return; | |
| 195 | case UNW_X86_EDI: | |
| 196 | _registers.__edi = value; | |
| 197 | return; | |
| 198 | } | |
| 199 | _LIBUNWIND_ABORT("unsupported x86 register"); | |
| 200 | } | |
| 201 | ||
| 202 | inline const char *Registers_x86::getRegisterName(int regNum) { | |
| 203 | switch (regNum) { | |
| 204 | case UNW_REG_IP: | |
| 205 | return "ip"; | |
| 206 | case UNW_REG_SP: | |
| 207 | return "esp"; | |
| 208 | case UNW_X86_EAX: | |
| 209 | return "eax"; | |
| 210 | case UNW_X86_ECX: | |
| 211 | return "ecx"; | |
| 212 | case UNW_X86_EDX: | |
| 213 | return "edx"; | |
| 214 | case UNW_X86_EBX: | |
| 215 | return "ebx"; | |
| 216 | case UNW_X86_EBP: | |
| 217 | return "ebp"; | |
| 218 | case UNW_X86_ESP: | |
| 219 | return "esp"; | |
| 220 | case UNW_X86_ESI: | |
| 221 | return "esi"; | |
| 222 | case UNW_X86_EDI: | |
| 223 | return "edi"; | |
| 224 | default: | |
| 225 | return "unknown register"; | |
| 226 | } | |
| 227 | } | |
| 228 | ||
| 229 | inline double Registers_x86::getFloatRegister(int) const { | |
| 230 | _LIBUNWIND_ABORT("no x86 float registers"); | |
| 231 | } | |
| 232 | ||
| 233 | inline void Registers_x86::setFloatRegister(int, double) { | |
| 234 | _LIBUNWIND_ABORT("no x86 float registers"); | |
| 235 | } | |
| 236 | ||
| 237 | inline v128 Registers_x86::getVectorRegister(int) const { | |
| 238 | _LIBUNWIND_ABORT("no x86 vector registers"); | |
| 239 | } | |
| 240 | ||
| 241 | inline void Registers_x86::setVectorRegister(int, v128) { | |
| 242 | _LIBUNWIND_ABORT("no x86 vector registers"); | |
| 243 | } | |
| 244 | #endif // _LIBUNWIND_TARGET_I386 | |
| 245 | ||
| 246 | ||
| 247 | #if defined(_LIBUNWIND_TARGET_X86_64) | |
| 248 | /// Registers_x86_64 holds the register state of a thread in a 64-bit intel | |
| 249 | /// process. | |
| 250 | class _LIBUNWIND_HIDDEN Registers_x86_64 { | |
| 251 | public: | |
| 252 | Registers_x86_64(); | |
| 253 | Registers_x86_64(const void *registers); | |
| 254 | ||
| 255 | bool validRegister(int num) const; | |
| 256 | uint64_t getRegister(int num) const; | |
| 257 | void setRegister(int num, uint64_t value); | |
| 258 | bool validFloatRegister(int) const { return false; } | |
| 259 | double getFloatRegister(int num) const; | |
| 260 | void setFloatRegister(int num, double value); | |
| 261 | bool validVectorRegister(int) const; | |
| 262 | v128 getVectorRegister(int num) const; | |
| 263 | void setVectorRegister(int num, v128 value); | |
| 264 | static const char *getRegisterName(int num); | |
| 265 | void jumpto(); | |
| 266 | static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64; } | |
| 267 | static int getArch() { return REGISTERS_X86_64; } | |
| 268 | ||
| 269 | uint64_t getSP() const { return _registers.__rsp; } | |
| 270 | void setSP(uint64_t value) { _registers.__rsp = value; } | |
| 271 | uint64_t getIP() const { return _registers.__rip; } | |
| 272 | void setIP(uint64_t value) { _registers.__rip = value; } | |
| 273 | uint64_t getRBP() const { return _registers.__rbp; } | |
| 274 | void setRBP(uint64_t value) { _registers.__rbp = value; } | |
| 275 | uint64_t getRBX() const { return _registers.__rbx; } | |
| 276 | void setRBX(uint64_t value) { _registers.__rbx = value; } | |
| 277 | uint64_t getR12() const { return _registers.__r12; } | |
| 278 | void setR12(uint64_t value) { _registers.__r12 = value; } | |
| 279 | uint64_t getR13() const { return _registers.__r13; } | |
| 280 | void setR13(uint64_t value) { _registers.__r13 = value; } | |
| 281 | uint64_t getR14() const { return _registers.__r14; } | |
| 282 | void setR14(uint64_t value) { _registers.__r14 = value; } | |
| 283 | uint64_t getR15() const { return _registers.__r15; } | |
| 284 | void setR15(uint64_t value) { _registers.__r15 = value; } | |
| 285 | ||
| 286 | private: | |
| 287 | struct GPRs { | |
| 288 | uint64_t __rax; | |
| 289 | uint64_t __rbx; | |
| 290 | uint64_t __rcx; | |
| 291 | uint64_t __rdx; | |
| 292 | uint64_t __rdi; | |
| 293 | uint64_t __rsi; | |
| 294 | uint64_t __rbp; | |
| 295 | uint64_t __rsp; | |
| 296 | uint64_t __r8; | |
| 297 | uint64_t __r9; | |
| 298 | uint64_t __r10; | |
| 299 | uint64_t __r11; | |
| 300 | uint64_t __r12; | |
| 301 | uint64_t __r13; | |
| 302 | uint64_t __r14; | |
| 303 | uint64_t __r15; | |
| 304 | uint64_t __rip; | |
| 305 | uint64_t __rflags; | |
| 306 | uint64_t __cs; | |
| 307 | uint64_t __fs; | |
| 308 | uint64_t __gs; | |
| 309 | #if defined(_WIN64) | |
| 310 | uint64_t __padding; // 16-byte align | |
| 311 | #endif | |
| 312 | }; | |
| 313 | GPRs _registers; | |
| 314 | #if defined(_WIN64) | |
| 315 | v128 _xmm[16]; | |
| 316 | #endif | |
| 317 | }; | |
| 318 | ||
| 319 | inline Registers_x86_64::Registers_x86_64(const void *registers) { | |
| 320 | static_assert((check_fit<Registers_x86_64, unw_context_t>::does_fit), | |
| 321 | "x86_64 registers do not fit into unw_context_t"); | |
| 322 | memcpy(&_registers, registers, sizeof(_registers)); | |
| 323 | } | |
| 324 | ||
| 325 | inline Registers_x86_64::Registers_x86_64() { | |
| 326 | memset(&_registers, 0, sizeof(_registers)); | |
| 327 | } | |
| 328 | ||
| 329 | inline bool Registers_x86_64::validRegister(int regNum) const { | |
| 330 | if (regNum == UNW_REG_IP) | |
| 331 | return true; | |
| 332 | if (regNum == UNW_REG_SP) | |
| 333 | return true; | |
| 334 | if (regNum < 0) | |
| 335 | return false; | |
| 336 | if (regNum > 15) | |
| 337 | return false; | |
| 338 | return true; | |
| 339 | } | |
| 340 | ||
| 341 | inline uint64_t Registers_x86_64::getRegister(int regNum) const { | |
| 342 | switch (regNum) { | |
| 343 | case UNW_REG_IP: | |
| 344 | return _registers.__rip; | |
| 345 | case UNW_REG_SP: | |
| 346 | return _registers.__rsp; | |
| 347 | case UNW_X86_64_RAX: | |
| 348 | return _registers.__rax; | |
| 349 | case UNW_X86_64_RDX: | |
| 350 | return _registers.__rdx; | |
| 351 | case UNW_X86_64_RCX: | |
| 352 | return _registers.__rcx; | |
| 353 | case UNW_X86_64_RBX: | |
| 354 | return _registers.__rbx; | |
| 355 | case UNW_X86_64_RSI: | |
| 356 | return _registers.__rsi; | |
| 357 | case UNW_X86_64_RDI: | |
| 358 | return _registers.__rdi; | |
| 359 | case UNW_X86_64_RBP: | |
| 360 | return _registers.__rbp; | |
| 361 | case UNW_X86_64_RSP: | |
| 362 | return _registers.__rsp; | |
| 363 | case UNW_X86_64_R8: | |
| 364 | return _registers.__r8; | |
| 365 | case UNW_X86_64_R9: | |
| 366 | return _registers.__r9; | |
| 367 | case UNW_X86_64_R10: | |
| 368 | return _registers.__r10; | |
| 369 | case UNW_X86_64_R11: | |
| 370 | return _registers.__r11; | |
| 371 | case UNW_X86_64_R12: | |
| 372 | return _registers.__r12; | |
| 373 | case UNW_X86_64_R13: | |
| 374 | return _registers.__r13; | |
| 375 | case UNW_X86_64_R14: | |
| 376 | return _registers.__r14; | |
| 377 | case UNW_X86_64_R15: | |
| 378 | return _registers.__r15; | |
| 379 | } | |
| 380 | _LIBUNWIND_ABORT("unsupported x86_64 register"); | |
| 381 | } | |
| 382 | ||
| 383 | inline void Registers_x86_64::setRegister(int regNum, uint64_t value) { | |
| 384 | switch (regNum) { | |
| 385 | case UNW_REG_IP: | |
| 386 | _registers.__rip = value; | |
| 387 | return; | |
| 388 | case UNW_REG_SP: | |
| 389 | _registers.__rsp = value; | |
| 390 | return; | |
| 391 | case UNW_X86_64_RAX: | |
| 392 | _registers.__rax = value; | |
| 393 | return; | |
| 394 | case UNW_X86_64_RDX: | |
| 395 | _registers.__rdx = value; | |
| 396 | return; | |
| 397 | case UNW_X86_64_RCX: | |
| 398 | _registers.__rcx = value; | |
| 399 | return; | |
| 400 | case UNW_X86_64_RBX: | |
| 401 | _registers.__rbx = value; | |
| 402 | return; | |
| 403 | case UNW_X86_64_RSI: | |
| 404 | _registers.__rsi = value; | |
| 405 | return; | |
| 406 | case UNW_X86_64_RDI: | |
| 407 | _registers.__rdi = value; | |
| 408 | return; | |
| 409 | case UNW_X86_64_RBP: | |
| 410 | _registers.__rbp = value; | |
| 411 | return; | |
| 412 | case UNW_X86_64_RSP: | |
| 413 | _registers.__rsp = value; | |
| 414 | return; | |
| 415 | case UNW_X86_64_R8: | |
| 416 | _registers.__r8 = value; | |
| 417 | return; | |
| 418 | case UNW_X86_64_R9: | |
| 419 | _registers.__r9 = value; | |
| 420 | return; | |
| 421 | case UNW_X86_64_R10: | |
| 422 | _registers.__r10 = value; | |
| 423 | return; | |
| 424 | case UNW_X86_64_R11: | |
| 425 | _registers.__r11 = value; | |
| 426 | return; | |
| 427 | case UNW_X86_64_R12: | |
| 428 | _registers.__r12 = value; | |
| 429 | return; | |
| 430 | case UNW_X86_64_R13: | |
| 431 | _registers.__r13 = value; | |
| 432 | return; | |
| 433 | case UNW_X86_64_R14: | |
| 434 | _registers.__r14 = value; | |
| 435 | return; | |
| 436 | case UNW_X86_64_R15: | |
| 437 | _registers.__r15 = value; | |
| 438 | return; | |
| 439 | } | |
| 440 | _LIBUNWIND_ABORT("unsupported x86_64 register"); | |
| 441 | } | |
| 442 | ||
| 443 | inline const char *Registers_x86_64::getRegisterName(int regNum) { | |
| 444 | switch (regNum) { | |
| 445 | case UNW_REG_IP: | |
| 446 | return "rip"; | |
| 447 | case UNW_REG_SP: | |
| 448 | return "rsp"; | |
| 449 | case UNW_X86_64_RAX: | |
| 450 | return "rax"; | |
| 451 | case UNW_X86_64_RDX: | |
| 452 | return "rdx"; | |
| 453 | case UNW_X86_64_RCX: | |
| 454 | return "rcx"; | |
| 455 | case UNW_X86_64_RBX: | |
| 456 | return "rbx"; | |
| 457 | case UNW_X86_64_RSI: | |
| 458 | return "rsi"; | |
| 459 | case UNW_X86_64_RDI: | |
| 460 | return "rdi"; | |
| 461 | case UNW_X86_64_RBP: | |
| 462 | return "rbp"; | |
| 463 | case UNW_X86_64_RSP: | |
| 464 | return "rsp"; | |
| 465 | case UNW_X86_64_R8: | |
| 466 | return "r8"; | |
| 467 | case UNW_X86_64_R9: | |
| 468 | return "r9"; | |
| 469 | case UNW_X86_64_R10: | |
| 470 | return "r10"; | |
| 471 | case UNW_X86_64_R11: | |
| 472 | return "r11"; | |
| 473 | case UNW_X86_64_R12: | |
| 474 | return "r12"; | |
| 475 | case UNW_X86_64_R13: | |
| 476 | return "r13"; | |
| 477 | case UNW_X86_64_R14: | |
| 478 | return "r14"; | |
| 479 | case UNW_X86_64_R15: | |
| 480 | return "r15"; | |
| 481 | case UNW_X86_64_XMM0: | |
| 482 | return "xmm0"; | |
| 483 | case UNW_X86_64_XMM1: | |
| 484 | return "xmm1"; | |
| 485 | case UNW_X86_64_XMM2: | |
| 486 | return "xmm2"; | |
| 487 | case UNW_X86_64_XMM3: | |
| 488 | return "xmm3"; | |
| 489 | case UNW_X86_64_XMM4: | |
| 490 | return "xmm4"; | |
| 491 | case UNW_X86_64_XMM5: | |
| 492 | return "xmm5"; | |
| 493 | case UNW_X86_64_XMM6: | |
| 494 | return "xmm6"; | |
| 495 | case UNW_X86_64_XMM7: | |
| 496 | return "xmm7"; | |
| 497 | case UNW_X86_64_XMM8: | |
| 498 | return "xmm8"; | |
| 499 | case UNW_X86_64_XMM9: | |
| 500 | return "xmm9"; | |
| 501 | case UNW_X86_64_XMM10: | |
| 502 | return "xmm10"; | |
| 503 | case UNW_X86_64_XMM11: | |
| 504 | return "xmm11"; | |
| 505 | case UNW_X86_64_XMM12: | |
| 506 | return "xmm12"; | |
| 507 | case UNW_X86_64_XMM13: | |
| 508 | return "xmm13"; | |
| 509 | case UNW_X86_64_XMM14: | |
| 510 | return "xmm14"; | |
| 511 | case UNW_X86_64_XMM15: | |
| 512 | return "xmm15"; | |
| 513 | default: | |
| 514 | return "unknown register"; | |
| 515 | } | |
| 516 | } | |
| 517 | ||
| 518 | inline double Registers_x86_64::getFloatRegister(int) const { | |
| 519 | _LIBUNWIND_ABORT("no x86_64 float registers"); | |
| 520 | } | |
| 521 | ||
| 522 | inline void Registers_x86_64::setFloatRegister(int, double) { | |
| 523 | _LIBUNWIND_ABORT("no x86_64 float registers"); | |
| 524 | } | |
| 525 | ||
| 526 | inline bool Registers_x86_64::validVectorRegister(int regNum) const { | |
| 527 | #if defined(_WIN64) | |
| 528 | if (regNum < UNW_X86_64_XMM0) | |
| 529 | return false; | |
| 530 | if (regNum > UNW_X86_64_XMM15) | |
| 531 | return false; | |
| 532 | return true; | |
| 533 | #else | |
| 534 | (void)regNum; // suppress unused parameter warning | |
| 535 | return false; | |
| 536 | #endif | |
| 537 | } | |
| 538 | ||
| 539 | inline v128 Registers_x86_64::getVectorRegister(int regNum) const { | |
| 540 | #if defined(_WIN64) | |
| 541 | assert(validVectorRegister(regNum)); | |
| 542 | return _xmm[regNum - UNW_X86_64_XMM0]; | |
| 543 | #else | |
| 544 | (void)regNum; // suppress unused parameter warning | |
| 545 | _LIBUNWIND_ABORT("no x86_64 vector registers"); | |
| 546 | #endif | |
| 547 | } | |
| 548 | ||
| 549 | inline void Registers_x86_64::setVectorRegister(int regNum, v128 value) { | |
| 550 | #if defined(_WIN64) | |
| 551 | assert(validVectorRegister(regNum)); | |
| 552 | _xmm[regNum - UNW_X86_64_XMM0] = value; | |
| 553 | #else | |
| 554 | (void)regNum; (void)value; // suppress unused parameter warnings | |
| 555 | _LIBUNWIND_ABORT("no x86_64 vector registers"); | |
| 556 | #endif | |
| 557 | } | |
| 558 | #endif // _LIBUNWIND_TARGET_X86_64 | |
| 559 | ||
| 560 | ||
| 561 | #if defined(_LIBUNWIND_TARGET_PPC) | |
| 562 | /// Registers_ppc holds the register state of a thread in a 32-bit PowerPC | |
| 563 | /// process. | |
| 564 | class _LIBUNWIND_HIDDEN Registers_ppc { | |
| 565 | public: | |
| 566 | Registers_ppc(); | |
| 567 | Registers_ppc(const void *registers); | |
| 568 | ||
| 569 | bool validRegister(int num) const; | |
| 570 | uint32_t getRegister(int num) const; | |
| 571 | void setRegister(int num, uint32_t value); | |
| 572 | bool validFloatRegister(int num) const; | |
| 573 | double getFloatRegister(int num) const; | |
| 574 | void setFloatRegister(int num, double value); | |
| 575 | bool validVectorRegister(int num) const; | |
| 576 | v128 getVectorRegister(int num) const; | |
| 577 | void setVectorRegister(int num, v128 value); | |
| 578 | static const char *getRegisterName(int num); | |
| 579 | void jumpto(); | |
| 580 | static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC; } | |
| 581 | static int getArch() { return REGISTERS_PPC; } | |
| 582 | ||
| 583 | uint64_t getSP() const { return _registers.__r1; } | |
| 584 | void setSP(uint32_t value) { _registers.__r1 = value; } | |
| 585 | uint64_t getIP() const { return _registers.__srr0; } | |
| 586 | void setIP(uint32_t value) { _registers.__srr0 = value; } | |
| 587 | ||
| 588 | private: | |
| 589 | struct ppc_thread_state_t { | |
| 590 | unsigned int __srr0; /* Instruction address register (PC) */ | |
| 591 | unsigned int __srr1; /* Machine state register (supervisor) */ | |
| 592 | unsigned int __r0; | |
| 593 | unsigned int __r1; | |
| 594 | unsigned int __r2; | |
| 595 | unsigned int __r3; | |
| 596 | unsigned int __r4; | |
| 597 | unsigned int __r5; | |
| 598 | unsigned int __r6; | |
| 599 | unsigned int __r7; | |
| 600 | unsigned int __r8; | |
| 601 | unsigned int __r9; | |
| 602 | unsigned int __r10; | |
| 603 | unsigned int __r11; | |
| 604 | unsigned int __r12; | |
| 605 | unsigned int __r13; | |
| 606 | unsigned int __r14; | |
| 607 | unsigned int __r15; | |
| 608 | unsigned int __r16; | |
| 609 | unsigned int __r17; | |
| 610 | unsigned int __r18; | |
| 611 | unsigned int __r19; | |
| 612 | unsigned int __r20; | |
| 613 | unsigned int __r21; | |
| 614 | unsigned int __r22; | |
| 615 | unsigned int __r23; | |
| 616 | unsigned int __r24; | |
| 617 | unsigned int __r25; | |
| 618 | unsigned int __r26; | |
| 619 | unsigned int __r27; | |
| 620 | unsigned int __r28; | |
| 621 | unsigned int __r29; | |
| 622 | unsigned int __r30; | |
| 623 | unsigned int __r31; | |
| 624 | unsigned int __cr; /* Condition register */ | |
| 625 | unsigned int __xer; /* User's integer exception register */ | |
| 626 | unsigned int __lr; /* Link register */ | |
| 627 | unsigned int __ctr; /* Count register */ | |
| 628 | unsigned int __mq; /* MQ register (601 only) */ | |
| 629 | unsigned int __vrsave; /* Vector Save Register */ | |
| 630 | }; | |
| 631 | ||
| 632 | struct ppc_float_state_t { | |
| 633 | double __fpregs[32]; | |
| 634 | ||
| 635 | unsigned int __fpscr_pad; /* fpscr is 64 bits, 32 bits of rubbish */ | |
| 636 | unsigned int __fpscr; /* floating point status register */ | |
| 637 | }; | |
| 638 | ||
| 639 | ppc_thread_state_t _registers; | |
| 640 | ppc_float_state_t _floatRegisters; | |
| 641 | v128 _vectorRegisters[32]; // offset 424 | |
| 642 | }; | |
| 643 | ||
| 644 | inline Registers_ppc::Registers_ppc(const void *registers) { | |
| 645 | static_assert((check_fit<Registers_ppc, unw_context_t>::does_fit), | |
| 646 | "ppc registers do not fit into unw_context_t"); | |
| 647 | memcpy(&_registers, static_cast<const uint8_t *>(registers), | |
| 648 | sizeof(_registers)); | |
| 649 | static_assert(sizeof(ppc_thread_state_t) == 160, | |
| 650 | "expected float register offset to be 160"); | |
| 651 | memcpy(&_floatRegisters, | |
| 652 | static_cast<const uint8_t *>(registers) + sizeof(ppc_thread_state_t), | |
| 653 | sizeof(_floatRegisters)); | |
| 654 | static_assert(sizeof(ppc_thread_state_t) + sizeof(ppc_float_state_t) == 424, | |
| 655 | "expected vector register offset to be 424 bytes"); | |
| 656 | memcpy(_vectorRegisters, | |
| 657 | static_cast<const uint8_t *>(registers) + sizeof(ppc_thread_state_t) + | |
| 658 | sizeof(ppc_float_state_t), | |
| 659 | sizeof(_vectorRegisters)); | |
| 660 | } | |
| 661 | ||
| 662 | inline Registers_ppc::Registers_ppc() { | |
| 663 | memset(&_registers, 0, sizeof(_registers)); | |
| 664 | memset(&_floatRegisters, 0, sizeof(_floatRegisters)); | |
| 665 | memset(&_vectorRegisters, 0, sizeof(_vectorRegisters)); | |
| 666 | } | |
| 667 | ||
| 668 | inline bool Registers_ppc::validRegister(int regNum) const { | |
| 669 | if (regNum == UNW_REG_IP) | |
| 670 | return true; | |
| 671 | if (regNum == UNW_REG_SP) | |
| 672 | return true; | |
| 673 | if (regNum == UNW_PPC_VRSAVE) | |
| 674 | return true; | |
| 675 | if (regNum < 0) | |
| 676 | return false; | |
| 677 | if (regNum <= UNW_PPC_R31) | |
| 678 | return true; | |
| 679 | if (regNum == UNW_PPC_MQ) | |
| 680 | return true; | |
| 681 | if (regNum == UNW_PPC_LR) | |
| 682 | return true; | |
| 683 | if (regNum == UNW_PPC_CTR) | |
| 684 | return true; | |
| 685 | if ((UNW_PPC_CR0 <= regNum) && (regNum <= UNW_PPC_CR7)) | |
| 686 | return true; | |
| 687 | return false; | |
| 688 | } | |
| 689 | ||
| 690 | inline uint32_t Registers_ppc::getRegister(int regNum) const { | |
| 691 | switch (regNum) { | |
| 692 | case UNW_REG_IP: | |
| 693 | return _registers.__srr0; | |
| 694 | case UNW_REG_SP: | |
| 695 | return _registers.__r1; | |
| 696 | case UNW_PPC_R0: | |
| 697 | return _registers.__r0; | |
| 698 | case UNW_PPC_R1: | |
| 699 | return _registers.__r1; | |
| 700 | case UNW_PPC_R2: | |
| 701 | return _registers.__r2; | |
| 702 | case UNW_PPC_R3: | |
| 703 | return _registers.__r3; | |
| 704 | case UNW_PPC_R4: | |
| 705 | return _registers.__r4; | |
| 706 | case UNW_PPC_R5: | |
| 707 | return _registers.__r5; | |
| 708 | case UNW_PPC_R6: | |
| 709 | return _registers.__r6; | |
| 710 | case UNW_PPC_R7: | |
| 711 | return _registers.__r7; | |
| 712 | case UNW_PPC_R8: | |
| 713 | return _registers.__r8; | |
| 714 | case UNW_PPC_R9: | |
| 715 | return _registers.__r9; | |
| 716 | case UNW_PPC_R10: | |
| 717 | return _registers.__r10; | |
| 718 | case UNW_PPC_R11: | |
| 719 | return _registers.__r11; | |
| 720 | case UNW_PPC_R12: | |
| 721 | return _registers.__r12; | |
| 722 | case UNW_PPC_R13: | |
| 723 | return _registers.__r13; | |
| 724 | case UNW_PPC_R14: | |
| 725 | return _registers.__r14; | |
| 726 | case UNW_PPC_R15: | |
| 727 | return _registers.__r15; | |
| 728 | case UNW_PPC_R16: | |
| 729 | return _registers.__r16; | |
| 730 | case UNW_PPC_R17: | |
| 731 | return _registers.__r17; | |
| 732 | case UNW_PPC_R18: | |
| 733 | return _registers.__r18; | |
| 734 | case UNW_PPC_R19: | |
| 735 | return _registers.__r19; | |
| 736 | case UNW_PPC_R20: | |
| 737 | return _registers.__r20; | |
| 738 | case UNW_PPC_R21: | |
| 739 | return _registers.__r21; | |
| 740 | case UNW_PPC_R22: | |
| 741 | return _registers.__r22; | |
| 742 | case UNW_PPC_R23: | |
| 743 | return _registers.__r23; | |
| 744 | case UNW_PPC_R24: | |
| 745 | return _registers.__r24; | |
| 746 | case UNW_PPC_R25: | |
| 747 | return _registers.__r25; | |
| 748 | case UNW_PPC_R26: | |
| 749 | return _registers.__r26; | |
| 750 | case UNW_PPC_R27: | |
| 751 | return _registers.__r27; | |
| 752 | case UNW_PPC_R28: | |
| 753 | return _registers.__r28; | |
| 754 | case UNW_PPC_R29: | |
| 755 | return _registers.__r29; | |
| 756 | case UNW_PPC_R30: | |
| 757 | return _registers.__r30; | |
| 758 | case UNW_PPC_R31: | |
| 759 | return _registers.__r31; | |
| 760 | case UNW_PPC_LR: | |
| 761 | return _registers.__lr; | |
| 762 | case UNW_PPC_CR0: | |
| 763 | return (_registers.__cr & 0xF0000000); | |
| 764 | case UNW_PPC_CR1: | |
| 765 | return (_registers.__cr & 0x0F000000); | |
| 766 | case UNW_PPC_CR2: | |
| 767 | return (_registers.__cr & 0x00F00000); | |
| 768 | case UNW_PPC_CR3: | |
| 769 | return (_registers.__cr & 0x000F0000); | |
| 770 | case UNW_PPC_CR4: | |
| 771 | return (_registers.__cr & 0x0000F000); | |
| 772 | case UNW_PPC_CR5: | |
| 773 | return (_registers.__cr & 0x00000F00); | |
| 774 | case UNW_PPC_CR6: | |
| 775 | return (_registers.__cr & 0x000000F0); | |
| 776 | case UNW_PPC_CR7: | |
| 777 | return (_registers.__cr & 0x0000000F); | |
| 778 | case UNW_PPC_VRSAVE: | |
| 779 | return _registers.__vrsave; | |
| 780 | } | |
| 781 | _LIBUNWIND_ABORT("unsupported ppc register"); | |
| 782 | } | |
| 783 | ||
| 784 | inline void Registers_ppc::setRegister(int regNum, uint32_t value) { | |
| 785 | //fprintf(stderr, "Registers_ppc::setRegister(%d, 0x%08X)\n", regNum, value); | |
| 786 | switch (regNum) { | |
| 787 | case UNW_REG_IP: | |
| 788 | _registers.__srr0 = value; | |
| 789 | return; | |
| 790 | case UNW_REG_SP: | |
| 791 | _registers.__r1 = value; | |
| 792 | return; | |
| 793 | case UNW_PPC_R0: | |
| 794 | _registers.__r0 = value; | |
| 795 | return; | |
| 796 | case UNW_PPC_R1: | |
| 797 | _registers.__r1 = value; | |
| 798 | return; | |
| 799 | case UNW_PPC_R2: | |
| 800 | _registers.__r2 = value; | |
| 801 | return; | |
| 802 | case UNW_PPC_R3: | |
| 803 | _registers.__r3 = value; | |
| 804 | return; | |
| 805 | case UNW_PPC_R4: | |
| 806 | _registers.__r4 = value; | |
| 807 | return; | |
| 808 | case UNW_PPC_R5: | |
| 809 | _registers.__r5 = value; | |
| 810 | return; | |
| 811 | case UNW_PPC_R6: | |
| 812 | _registers.__r6 = value; | |
| 813 | return; | |
| 814 | case UNW_PPC_R7: | |
| 815 | _registers.__r7 = value; | |
| 816 | return; | |
| 817 | case UNW_PPC_R8: | |
| 818 | _registers.__r8 = value; | |
| 819 | return; | |
| 820 | case UNW_PPC_R9: | |
| 821 | _registers.__r9 = value; | |
| 822 | return; | |
| 823 | case UNW_PPC_R10: | |
| 824 | _registers.__r10 = value; | |
| 825 | return; | |
| 826 | case UNW_PPC_R11: | |
| 827 | _registers.__r11 = value; | |
| 828 | return; | |
| 829 | case UNW_PPC_R12: | |
| 830 | _registers.__r12 = value; | |
| 831 | return; | |
| 832 | case UNW_PPC_R13: | |
| 833 | _registers.__r13 = value; | |
| 834 | return; | |
| 835 | case UNW_PPC_R14: | |
| 836 | _registers.__r14 = value; | |
| 837 | return; | |
| 838 | case UNW_PPC_R15: | |
| 839 | _registers.__r15 = value; | |
| 840 | return; | |
| 841 | case UNW_PPC_R16: | |
| 842 | _registers.__r16 = value; | |
| 843 | return; | |
| 844 | case UNW_PPC_R17: | |
| 845 | _registers.__r17 = value; | |
| 846 | return; | |
| 847 | case UNW_PPC_R18: | |
| 848 | _registers.__r18 = value; | |
| 849 | return; | |
| 850 | case UNW_PPC_R19: | |
| 851 | _registers.__r19 = value; | |
| 852 | return; | |
| 853 | case UNW_PPC_R20: | |
| 854 | _registers.__r20 = value; | |
| 855 | return; | |
| 856 | case UNW_PPC_R21: | |
| 857 | _registers.__r21 = value; | |
| 858 | return; | |
| 859 | case UNW_PPC_R22: | |
| 860 | _registers.__r22 = value; | |
| 861 | return; | |
| 862 | case UNW_PPC_R23: | |
| 863 | _registers.__r23 = value; | |
| 864 | return; | |
| 865 | case UNW_PPC_R24: | |
| 866 | _registers.__r24 = value; | |
| 867 | return; | |
| 868 | case UNW_PPC_R25: | |
| 869 | _registers.__r25 = value; | |
| 870 | return; | |
| 871 | case UNW_PPC_R26: | |
| 872 | _registers.__r26 = value; | |
| 873 | return; | |
| 874 | case UNW_PPC_R27: | |
| 875 | _registers.__r27 = value; | |
| 876 | return; | |
| 877 | case UNW_PPC_R28: | |
| 878 | _registers.__r28 = value; | |
| 879 | return; | |
| 880 | case UNW_PPC_R29: | |
| 881 | _registers.__r29 = value; | |
| 882 | return; | |
| 883 | case UNW_PPC_R30: | |
| 884 | _registers.__r30 = value; | |
| 885 | return; | |
| 886 | case UNW_PPC_R31: | |
| 887 | _registers.__r31 = value; | |
| 888 | return; | |
| 889 | case UNW_PPC_MQ: | |
| 890 | _registers.__mq = value; | |
| 891 | return; | |
| 892 | case UNW_PPC_LR: | |
| 893 | _registers.__lr = value; | |
| 894 | return; | |
| 895 | case UNW_PPC_CTR: | |
| 896 | _registers.__ctr = value; | |
| 897 | return; | |
| 898 | case UNW_PPC_CR0: | |
| 899 | _registers.__cr &= 0x0FFFFFFF; | |
| 900 | _registers.__cr |= (value & 0xF0000000); | |
| 901 | return; | |
| 902 | case UNW_PPC_CR1: | |
| 903 | _registers.__cr &= 0xF0FFFFFF; | |
| 904 | _registers.__cr |= (value & 0x0F000000); | |
| 905 | return; | |
| 906 | case UNW_PPC_CR2: | |
| 907 | _registers.__cr &= 0xFF0FFFFF; | |
| 908 | _registers.__cr |= (value & 0x00F00000); | |
| 909 | return; | |
| 910 | case UNW_PPC_CR3: | |
| 911 | _registers.__cr &= 0xFFF0FFFF; | |
| 912 | _registers.__cr |= (value & 0x000F0000); | |
| 913 | return; | |
| 914 | case UNW_PPC_CR4: | |
| 915 | _registers.__cr &= 0xFFFF0FFF; | |
| 916 | _registers.__cr |= (value & 0x0000F000); | |
| 917 | return; | |
| 918 | case UNW_PPC_CR5: | |
| 919 | _registers.__cr &= 0xFFFFF0FF; | |
| 920 | _registers.__cr |= (value & 0x00000F00); | |
| 921 | return; | |
| 922 | case UNW_PPC_CR6: | |
| 923 | _registers.__cr &= 0xFFFFFF0F; | |
| 924 | _registers.__cr |= (value & 0x000000F0); | |
| 925 | return; | |
| 926 | case UNW_PPC_CR7: | |
| 927 | _registers.__cr &= 0xFFFFFFF0; | |
| 928 | _registers.__cr |= (value & 0x0000000F); | |
| 929 | return; | |
| 930 | case UNW_PPC_VRSAVE: | |
| 931 | _registers.__vrsave = value; | |
| 932 | return; | |
| 933 | // not saved | |
| 934 | return; | |
| 935 | case UNW_PPC_XER: | |
| 936 | _registers.__xer = value; | |
| 937 | return; | |
| 938 | case UNW_PPC_AP: | |
| 939 | case UNW_PPC_VSCR: | |
| 940 | case UNW_PPC_SPEFSCR: | |
| 941 | // not saved | |
| 942 | return; | |
| 943 | } | |
| 944 | _LIBUNWIND_ABORT("unsupported ppc register"); | |
| 945 | } | |
| 946 | ||
| 947 | inline bool Registers_ppc::validFloatRegister(int regNum) const { | |
| 948 | if (regNum < UNW_PPC_F0) | |
| 949 | return false; | |
| 950 | if (regNum > UNW_PPC_F31) | |
| 951 | return false; | |
| 952 | return true; | |
| 953 | } | |
| 954 | ||
| 955 | inline double Registers_ppc::getFloatRegister(int regNum) const { | |
| 956 | assert(validFloatRegister(regNum)); | |
| 957 | return _floatRegisters.__fpregs[regNum - UNW_PPC_F0]; | |
| 958 | } | |
| 959 | ||
| 960 | inline void Registers_ppc::setFloatRegister(int regNum, double value) { | |
| 961 | assert(validFloatRegister(regNum)); | |
| 962 | _floatRegisters.__fpregs[regNum - UNW_PPC_F0] = value; | |
| 963 | } | |
| 964 | ||
| 965 | inline bool Registers_ppc::validVectorRegister(int regNum) const { | |
| 966 | if (regNum < UNW_PPC_V0) | |
| 967 | return false; | |
| 968 | if (regNum > UNW_PPC_V31) | |
| 969 | return false; | |
| 970 | return true; | |
| 971 | } | |
| 972 | ||
| 973 | inline v128 Registers_ppc::getVectorRegister(int regNum) const { | |
| 974 | assert(validVectorRegister(regNum)); | |
| 975 | v128 result = _vectorRegisters[regNum - UNW_PPC_V0]; | |
| 976 | return result; | |
| 977 | } | |
| 978 | ||
| 979 | inline void Registers_ppc::setVectorRegister(int regNum, v128 value) { | |
| 980 | assert(validVectorRegister(regNum)); | |
| 981 | _vectorRegisters[regNum - UNW_PPC_V0] = value; | |
| 982 | } | |
| 983 | ||
| 984 | inline const char *Registers_ppc::getRegisterName(int regNum) { | |
| 985 | switch (regNum) { | |
| 986 | case UNW_REG_IP: | |
| 987 | return "ip"; | |
| 988 | case UNW_REG_SP: | |
| 989 | return "sp"; | |
| 990 | case UNW_PPC_R0: | |
| 991 | return "r0"; | |
| 992 | case UNW_PPC_R1: | |
| 993 | return "r1"; | |
| 994 | case UNW_PPC_R2: | |
| 995 | return "r2"; | |
| 996 | case UNW_PPC_R3: | |
| 997 | return "r3"; | |
| 998 | case UNW_PPC_R4: | |
| 999 | return "r4"; | |
| 1000 | case UNW_PPC_R5: | |
| 1001 | return "r5"; | |
| 1002 | case UNW_PPC_R6: | |
| 1003 | return "r6"; | |
| 1004 | case UNW_PPC_R7: | |
| 1005 | return "r7"; | |
| 1006 | case UNW_PPC_R8: | |
| 1007 | return "r8"; | |
| 1008 | case UNW_PPC_R9: | |
| 1009 | return "r9"; | |
| 1010 | case UNW_PPC_R10: | |
| 1011 | return "r10"; | |
| 1012 | case UNW_PPC_R11: | |
| 1013 | return "r11"; | |
| 1014 | case UNW_PPC_R12: | |
| 1015 | return "r12"; | |
| 1016 | case UNW_PPC_R13: | |
| 1017 | return "r13"; | |
| 1018 | case UNW_PPC_R14: | |
| 1019 | return "r14"; | |
| 1020 | case UNW_PPC_R15: | |
| 1021 | return "r15"; | |
| 1022 | case UNW_PPC_R16: | |
| 1023 | return "r16"; | |
| 1024 | case UNW_PPC_R17: | |
| 1025 | return "r17"; | |
| 1026 | case UNW_PPC_R18: | |
| 1027 | return "r18"; | |
| 1028 | case UNW_PPC_R19: | |
| 1029 | return "r19"; | |
| 1030 | case UNW_PPC_R20: | |
| 1031 | return "r20"; | |
| 1032 | case UNW_PPC_R21: | |
| 1033 | return "r21"; | |
| 1034 | case UNW_PPC_R22: | |
| 1035 | return "r22"; | |
| 1036 | case UNW_PPC_R23: | |
| 1037 | return "r23"; | |
| 1038 | case UNW_PPC_R24: | |
| 1039 | return "r24"; | |
| 1040 | case UNW_PPC_R25: | |
| 1041 | return "r25"; | |
| 1042 | case UNW_PPC_R26: | |
| 1043 | return "r26"; | |
| 1044 | case UNW_PPC_R27: | |
| 1045 | return "r27"; | |
| 1046 | case UNW_PPC_R28: | |
| 1047 | return "r28"; | |
| 1048 | case UNW_PPC_R29: | |
| 1049 | return "r29"; | |
| 1050 | case UNW_PPC_R30: | |
| 1051 | return "r30"; | |
| 1052 | case UNW_PPC_R31: | |
| 1053 | return "r31"; | |
| 1054 | case UNW_PPC_F0: | |
| 1055 | return "fp0"; | |
| 1056 | case UNW_PPC_F1: | |
| 1057 | return "fp1"; | |
| 1058 | case UNW_PPC_F2: | |
| 1059 | return "fp2"; | |
| 1060 | case UNW_PPC_F3: | |
| 1061 | return "fp3"; | |
| 1062 | case UNW_PPC_F4: | |
| 1063 | return "fp4"; | |
| 1064 | case UNW_PPC_F5: | |
| 1065 | return "fp5"; | |
| 1066 | case UNW_PPC_F6: | |
| 1067 | return "fp6"; | |
| 1068 | case UNW_PPC_F7: | |
| 1069 | return "fp7"; | |
| 1070 | case UNW_PPC_F8: | |
| 1071 | return "fp8"; | |
| 1072 | case UNW_PPC_F9: | |
| 1073 | return "fp9"; | |
| 1074 | case UNW_PPC_F10: | |
| 1075 | return "fp10"; | |
| 1076 | case UNW_PPC_F11: | |
| 1077 | return "fp11"; | |
| 1078 | case UNW_PPC_F12: | |
| 1079 | return "fp12"; | |
| 1080 | case UNW_PPC_F13: | |
| 1081 | return "fp13"; | |
| 1082 | case UNW_PPC_F14: | |
| 1083 | return "fp14"; | |
| 1084 | case UNW_PPC_F15: | |
| 1085 | return "fp15"; | |
| 1086 | case UNW_PPC_F16: | |
| 1087 | return "fp16"; | |
| 1088 | case UNW_PPC_F17: | |
| 1089 | return "fp17"; | |
| 1090 | case UNW_PPC_F18: | |
| 1091 | return "fp18"; | |
| 1092 | case UNW_PPC_F19: | |
| 1093 | return "fp19"; | |
| 1094 | case UNW_PPC_F20: | |
| 1095 | return "fp20"; | |
| 1096 | case UNW_PPC_F21: | |
| 1097 | return "fp21"; | |
| 1098 | case UNW_PPC_F22: | |
| 1099 | return "fp22"; | |
| 1100 | case UNW_PPC_F23: | |
| 1101 | return "fp23"; | |
| 1102 | case UNW_PPC_F24: | |
| 1103 | return "fp24"; | |
| 1104 | case UNW_PPC_F25: | |
| 1105 | return "fp25"; | |
| 1106 | case UNW_PPC_F26: | |
| 1107 | return "fp26"; | |
| 1108 | case UNW_PPC_F27: | |
| 1109 | return "fp27"; | |
| 1110 | case UNW_PPC_F28: | |
| 1111 | return "fp28"; | |
| 1112 | case UNW_PPC_F29: | |
| 1113 | return "fp29"; | |
| 1114 | case UNW_PPC_F30: | |
| 1115 | return "fp30"; | |
| 1116 | case UNW_PPC_F31: | |
| 1117 | return "fp31"; | |
| 1118 | case UNW_PPC_LR: | |
| 1119 | return "lr"; | |
| 1120 | default: | |
| 1121 | return "unknown register"; | |
| 1122 | } | |
| 1123 | ||
| 1124 | } | |
| 1125 | #endif // _LIBUNWIND_TARGET_PPC | |
| 1126 | ||
| 1127 | #if defined(_LIBUNWIND_TARGET_PPC64) | |
| 1128 | /// Registers_ppc64 holds the register state of a thread in a 64-bit PowerPC | |
| 1129 | /// process. | |
| 1130 | class _LIBUNWIND_HIDDEN Registers_ppc64 { | |
| 1131 | public: | |
| 1132 | Registers_ppc64(); | |
| 1133 | Registers_ppc64(const void *registers); | |
| 1134 | ||
| 1135 | bool validRegister(int num) const; | |
| 1136 | uint64_t getRegister(int num) const; | |
| 1137 | void setRegister(int num, uint64_t value); | |
| 1138 | bool validFloatRegister(int num) const; | |
| 1139 | double getFloatRegister(int num) const; | |
| 1140 | void setFloatRegister(int num, double value); | |
| 1141 | bool validVectorRegister(int num) const; | |
| 1142 | v128 getVectorRegister(int num) const; | |
| 1143 | void setVectorRegister(int num, v128 value); | |
| 1144 | static const char *getRegisterName(int num); | |
| 1145 | void jumpto(); | |
| 1146 | static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64; } | |
| 1147 | static int getArch() { return REGISTERS_PPC64; } | |
| 1148 | ||
| 1149 | uint64_t getSP() const { return _registers.__r1; } | |
| 1150 | void setSP(uint64_t value) { _registers.__r1 = value; } | |
| 1151 | uint64_t getIP() const { return _registers.__srr0; } | |
| 1152 | void setIP(uint64_t value) { _registers.__srr0 = value; } | |
| 1153 | ||
| 1154 | private: | |
| 1155 | struct ppc64_thread_state_t { | |
| 1156 | uint64_t __srr0; // Instruction address register (PC) | |
| 1157 | uint64_t __srr1; // Machine state register (supervisor) | |
| 1158 | uint64_t __r0; | |
| 1159 | uint64_t __r1; | |
| 1160 | uint64_t __r2; | |
| 1161 | uint64_t __r3; | |
| 1162 | uint64_t __r4; | |
| 1163 | uint64_t __r5; | |
| 1164 | uint64_t __r6; | |
| 1165 | uint64_t __r7; | |
| 1166 | uint64_t __r8; | |
| 1167 | uint64_t __r9; | |
| 1168 | uint64_t __r10; | |
| 1169 | uint64_t __r11; | |
| 1170 | uint64_t __r12; | |
| 1171 | uint64_t __r13; | |
| 1172 | uint64_t __r14; | |
| 1173 | uint64_t __r15; | |
| 1174 | uint64_t __r16; | |
| 1175 | uint64_t __r17; | |
| 1176 | uint64_t __r18; | |
| 1177 | uint64_t __r19; | |
| 1178 | uint64_t __r20; | |
| 1179 | uint64_t __r21; | |
| 1180 | uint64_t __r22; | |
| 1181 | uint64_t __r23; | |
| 1182 | uint64_t __r24; | |
| 1183 | uint64_t __r25; | |
| 1184 | uint64_t __r26; | |
| 1185 | uint64_t __r27; | |
| 1186 | uint64_t __r28; | |
| 1187 | uint64_t __r29; | |
| 1188 | uint64_t __r30; | |
| 1189 | uint64_t __r31; | |
| 1190 | uint64_t __cr; // Condition register | |
| 1191 | uint64_t __xer; // User's integer exception register | |
| 1192 | uint64_t __lr; // Link register | |
| 1193 | uint64_t __ctr; // Count register | |
| 1194 | uint64_t __vrsave; // Vector Save Register | |
| 1195 | }; | |
| 1196 | ||
| 1197 | union ppc64_vsr_t { | |
| 1198 | struct asfloat_s { | |
| 1199 | double f; | |
| 1200 | uint64_t v2; | |
| 1201 | } asfloat; | |
| 1202 | v128 v; | |
| 1203 | }; | |
| 1204 | ||
| 1205 | ppc64_thread_state_t _registers; | |
| 1206 | ppc64_vsr_t _vectorScalarRegisters[64]; | |
| 1207 | ||
| 1208 | static int getVectorRegNum(int num); | |
| 1209 | }; | |
| 1210 | ||
| 1211 | inline Registers_ppc64::Registers_ppc64(const void *registers) { | |
| 1212 | static_assert((check_fit<Registers_ppc64, unw_context_t>::does_fit), | |
| 1213 | "ppc64 registers do not fit into unw_context_t"); | |
| 1214 | memcpy(&_registers, static_cast<const uint8_t *>(registers), | |
| 1215 | sizeof(_registers)); | |
| 1216 | static_assert(sizeof(_registers) == 312, | |
| 1217 | "expected vector scalar register offset to be 312"); | |
| 1218 | memcpy(&_vectorScalarRegisters, | |
| 1219 | static_cast<const uint8_t *>(registers) + sizeof(_registers), | |
| 1220 | sizeof(_vectorScalarRegisters)); | |
| 1221 | static_assert(sizeof(_registers) + | |
| 1222 | sizeof(_vectorScalarRegisters) == 1336, | |
| 1223 | "expected vector register offset to be 1336 bytes"); | |
| 1224 | } | |
| 1225 | ||
| 1226 | inline Registers_ppc64::Registers_ppc64() { | |
| 1227 | memset(&_registers, 0, sizeof(_registers)); | |
| 1228 | memset(&_vectorScalarRegisters, 0, sizeof(_vectorScalarRegisters)); | |
| 1229 | } | |
| 1230 | ||
| 1231 | inline bool Registers_ppc64::validRegister(int regNum) const { | |
| 1232 | switch (regNum) { | |
| 1233 | case UNW_REG_IP: | |
| 1234 | case UNW_REG_SP: | |
| 1235 | case UNW_PPC64_XER: | |
| 1236 | case UNW_PPC64_LR: | |
| 1237 | case UNW_PPC64_CTR: | |
| 1238 | case UNW_PPC64_VRSAVE: | |
| 1239 | return true; | |
| 1240 | } | |
| 1241 | ||
| 1242 | if (regNum >= UNW_PPC64_R0 && regNum <= UNW_PPC64_R31) | |
| 1243 | return true; | |
| 1244 | if (regNum >= UNW_PPC64_CR0 && regNum <= UNW_PPC64_CR7) | |
| 1245 | return true; | |
| 1246 | ||
| 1247 | return false; | |
| 1248 | } | |
| 1249 | ||
| 1250 | inline uint64_t Registers_ppc64::getRegister(int regNum) const { | |
| 1251 | switch (regNum) { | |
| 1252 | case UNW_REG_IP: | |
| 1253 | return _registers.__srr0; | |
| 1254 | case UNW_PPC64_R0: | |
| 1255 | return _registers.__r0; | |
| 1256 | case UNW_PPC64_R1: | |
| 1257 | case UNW_REG_SP: | |
| 1258 | return _registers.__r1; | |
| 1259 | case UNW_PPC64_R2: | |
| 1260 | return _registers.__r2; | |
| 1261 | case UNW_PPC64_R3: | |
| 1262 | return _registers.__r3; | |
| 1263 | case UNW_PPC64_R4: | |
| 1264 | return _registers.__r4; | |
| 1265 | case UNW_PPC64_R5: | |
| 1266 | return _registers.__r5; | |
| 1267 | case UNW_PPC64_R6: | |
| 1268 | return _registers.__r6; | |
| 1269 | case UNW_PPC64_R7: | |
| 1270 | return _registers.__r7; | |
| 1271 | case UNW_PPC64_R8: | |
| 1272 | return _registers.__r8; | |
| 1273 | case UNW_PPC64_R9: | |
| 1274 | return _registers.__r9; | |
| 1275 | case UNW_PPC64_R10: | |
| 1276 | return _registers.__r10; | |
| 1277 | case UNW_PPC64_R11: | |
| 1278 | return _registers.__r11; | |
| 1279 | case UNW_PPC64_R12: | |
| 1280 | return _registers.__r12; | |
| 1281 | case UNW_PPC64_R13: | |
| 1282 | return _registers.__r13; | |
| 1283 | case UNW_PPC64_R14: | |
| 1284 | return _registers.__r14; | |
| 1285 | case UNW_PPC64_R15: | |
| 1286 | return _registers.__r15; | |
| 1287 | case UNW_PPC64_R16: | |
| 1288 | return _registers.__r16; | |
| 1289 | case UNW_PPC64_R17: | |
| 1290 | return _registers.__r17; | |
| 1291 | case UNW_PPC64_R18: | |
| 1292 | return _registers.__r18; | |
| 1293 | case UNW_PPC64_R19: | |
| 1294 | return _registers.__r19; | |
| 1295 | case UNW_PPC64_R20: | |
| 1296 | return _registers.__r20; | |
| 1297 | case UNW_PPC64_R21: | |
| 1298 | return _registers.__r21; | |
| 1299 | case UNW_PPC64_R22: | |
| 1300 | return _registers.__r22; | |
| 1301 | case UNW_PPC64_R23: | |
| 1302 | return _registers.__r23; | |
| 1303 | case UNW_PPC64_R24: | |
| 1304 | return _registers.__r24; | |
| 1305 | case UNW_PPC64_R25: | |
| 1306 | return _registers.__r25; | |
| 1307 | case UNW_PPC64_R26: | |
| 1308 | return _registers.__r26; | |
| 1309 | case UNW_PPC64_R27: | |
| 1310 | return _registers.__r27; | |
| 1311 | case UNW_PPC64_R28: | |
| 1312 | return _registers.__r28; | |
| 1313 | case UNW_PPC64_R29: | |
| 1314 | return _registers.__r29; | |
| 1315 | case UNW_PPC64_R30: | |
| 1316 | return _registers.__r30; | |
| 1317 | case UNW_PPC64_R31: | |
| 1318 | return _registers.__r31; | |
| 1319 | case UNW_PPC64_CR0: | |
| 1320 | return (_registers.__cr & 0xF0000000); | |
| 1321 | case UNW_PPC64_CR1: | |
| 1322 | return (_registers.__cr & 0x0F000000); | |
| 1323 | case UNW_PPC64_CR2: | |
| 1324 | return (_registers.__cr & 0x00F00000); | |
| 1325 | case UNW_PPC64_CR3: | |
| 1326 | return (_registers.__cr & 0x000F0000); | |
| 1327 | case UNW_PPC64_CR4: | |
| 1328 | return (_registers.__cr & 0x0000F000); | |
| 1329 | case UNW_PPC64_CR5: | |
| 1330 | return (_registers.__cr & 0x00000F00); | |
| 1331 | case UNW_PPC64_CR6: | |
| 1332 | return (_registers.__cr & 0x000000F0); | |
| 1333 | case UNW_PPC64_CR7: | |
| 1334 | return (_registers.__cr & 0x0000000F); | |
| 1335 | case UNW_PPC64_XER: | |
| 1336 | return _registers.__xer; | |
| 1337 | case UNW_PPC64_LR: | |
| 1338 | return _registers.__lr; | |
| 1339 | case UNW_PPC64_CTR: | |
| 1340 | return _registers.__ctr; | |
| 1341 | case UNW_PPC64_VRSAVE: | |
| 1342 | return _registers.__vrsave; | |
| 1343 | } | |
| 1344 | _LIBUNWIND_ABORT("unsupported ppc64 register"); | |
| 1345 | } | |
| 1346 | ||
| 1347 | inline void Registers_ppc64::setRegister(int regNum, uint64_t value) { | |
| 1348 | switch (regNum) { | |
| 1349 | case UNW_REG_IP: | |
| 1350 | _registers.__srr0 = value; | |
| 1351 | return; | |
| 1352 | case UNW_PPC64_R0: | |
| 1353 | _registers.__r0 = value; | |
| 1354 | return; | |
| 1355 | case UNW_PPC64_R1: | |
| 1356 | case UNW_REG_SP: | |
| 1357 | _registers.__r1 = value; | |
| 1358 | return; | |
| 1359 | case UNW_PPC64_R2: | |
| 1360 | _registers.__r2 = value; | |
| 1361 | return; | |
| 1362 | case UNW_PPC64_R3: | |
| 1363 | _registers.__r3 = value; | |
| 1364 | return; | |
| 1365 | case UNW_PPC64_R4: | |
| 1366 | _registers.__r4 = value; | |
| 1367 | return; | |
| 1368 | case UNW_PPC64_R5: | |
| 1369 | _registers.__r5 = value; | |
| 1370 | return; | |
| 1371 | case UNW_PPC64_R6: | |
| 1372 | _registers.__r6 = value; | |
| 1373 | return; | |
| 1374 | case UNW_PPC64_R7: | |
| 1375 | _registers.__r7 = value; | |
| 1376 | return; | |
| 1377 | case UNW_PPC64_R8: | |
| 1378 | _registers.__r8 = value; | |
| 1379 | return; | |
| 1380 | case UNW_PPC64_R9: | |
| 1381 | _registers.__r9 = value; | |
| 1382 | return; | |
| 1383 | case UNW_PPC64_R10: | |
| 1384 | _registers.__r10 = value; | |
| 1385 | return; | |
| 1386 | case UNW_PPC64_R11: | |
| 1387 | _registers.__r11 = value; | |
| 1388 | return; | |
| 1389 | case UNW_PPC64_R12: | |
| 1390 | _registers.__r12 = value; | |
| 1391 | return; | |
| 1392 | case UNW_PPC64_R13: | |
| 1393 | _registers.__r13 = value; | |
| 1394 | return; | |
| 1395 | case UNW_PPC64_R14: | |
| 1396 | _registers.__r14 = value; | |
| 1397 | return; | |
| 1398 | case UNW_PPC64_R15: | |
| 1399 | _registers.__r15 = value; | |
| 1400 | return; | |
| 1401 | case UNW_PPC64_R16: | |
| 1402 | _registers.__r16 = value; | |
| 1403 | return; | |
| 1404 | case UNW_PPC64_R17: | |
| 1405 | _registers.__r17 = value; | |
| 1406 | return; | |
| 1407 | case UNW_PPC64_R18: | |
| 1408 | _registers.__r18 = value; | |
| 1409 | return; | |
| 1410 | case UNW_PPC64_R19: | |
| 1411 | _registers.__r19 = value; | |
| 1412 | return; | |
| 1413 | case UNW_PPC64_R20: | |
| 1414 | _registers.__r20 = value; | |
| 1415 | return; | |
| 1416 | case UNW_PPC64_R21: | |
| 1417 | _registers.__r21 = value; | |
| 1418 | return; | |
| 1419 | case UNW_PPC64_R22: | |
| 1420 | _registers.__r22 = value; | |
| 1421 | return; | |
| 1422 | case UNW_PPC64_R23: | |
| 1423 | _registers.__r23 = value; | |
| 1424 | return; | |
| 1425 | case UNW_PPC64_R24: | |
| 1426 | _registers.__r24 = value; | |
| 1427 | return; | |
| 1428 | case UNW_PPC64_R25: | |
| 1429 | _registers.__r25 = value; | |
| 1430 | return; | |
| 1431 | case UNW_PPC64_R26: | |
| 1432 | _registers.__r26 = value; | |
| 1433 | return; | |
| 1434 | case UNW_PPC64_R27: | |
| 1435 | _registers.__r27 = value; | |
| 1436 | return; | |
| 1437 | case UNW_PPC64_R28: | |
| 1438 | _registers.__r28 = value; | |
| 1439 | return; | |
| 1440 | case UNW_PPC64_R29: | |
| 1441 | _registers.__r29 = value; | |
| 1442 | return; | |
| 1443 | case UNW_PPC64_R30: | |
| 1444 | _registers.__r30 = value; | |
| 1445 | return; | |
| 1446 | case UNW_PPC64_R31: | |
| 1447 | _registers.__r31 = value; | |
| 1448 | return; | |
| 1449 | case UNW_PPC64_CR0: | |
| 1450 | _registers.__cr &= 0x0FFFFFFF; | |
| 1451 | _registers.__cr |= (value & 0xF0000000); | |
| 1452 | return; | |
| 1453 | case UNW_PPC64_CR1: | |
| 1454 | _registers.__cr &= 0xF0FFFFFF; | |
| 1455 | _registers.__cr |= (value & 0x0F000000); | |
| 1456 | return; | |
| 1457 | case UNW_PPC64_CR2: | |
| 1458 | _registers.__cr &= 0xFF0FFFFF; | |
| 1459 | _registers.__cr |= (value & 0x00F00000); | |
| 1460 | return; | |
| 1461 | case UNW_PPC64_CR3: | |
| 1462 | _registers.__cr &= 0xFFF0FFFF; | |
| 1463 | _registers.__cr |= (value & 0x000F0000); | |
| 1464 | return; | |
| 1465 | case UNW_PPC64_CR4: | |
| 1466 | _registers.__cr &= 0xFFFF0FFF; | |
| 1467 | _registers.__cr |= (value & 0x0000F000); | |
| 1468 | return; | |
| 1469 | case UNW_PPC64_CR5: | |
| 1470 | _registers.__cr &= 0xFFFFF0FF; | |
| 1471 | _registers.__cr |= (value & 0x00000F00); | |
| 1472 | return; | |
| 1473 | case UNW_PPC64_CR6: | |
| 1474 | _registers.__cr &= 0xFFFFFF0F; | |
| 1475 | _registers.__cr |= (value & 0x000000F0); | |
| 1476 | return; | |
| 1477 | case UNW_PPC64_CR7: | |
| 1478 | _registers.__cr &= 0xFFFFFFF0; | |
| 1479 | _registers.__cr |= (value & 0x0000000F); | |
| 1480 | return; | |
| 1481 | case UNW_PPC64_XER: | |
| 1482 | _registers.__xer = value; | |
| 1483 | return; | |
| 1484 | case UNW_PPC64_LR: | |
| 1485 | _registers.__lr = value; | |
| 1486 | return; | |
| 1487 | case UNW_PPC64_CTR: | |
| 1488 | _registers.__ctr = value; | |
| 1489 | return; | |
| 1490 | case UNW_PPC64_VRSAVE: | |
| 1491 | _registers.__vrsave = value; | |
| 1492 | return; | |
| 1493 | } | |
| 1494 | _LIBUNWIND_ABORT("unsupported ppc64 register"); | |
| 1495 | } | |
| 1496 | ||
| 1497 | inline bool Registers_ppc64::validFloatRegister(int regNum) const { | |
| 1498 | return regNum >= UNW_PPC64_F0 && regNum <= UNW_PPC64_F31; | |
| 1499 | } | |
| 1500 | ||
| 1501 | inline double Registers_ppc64::getFloatRegister(int regNum) const { | |
| 1502 | assert(validFloatRegister(regNum)); | |
| 1503 | return _vectorScalarRegisters[regNum - UNW_PPC64_F0].asfloat.f; | |
| 1504 | } | |
| 1505 | ||
| 1506 | inline void Registers_ppc64::setFloatRegister(int regNum, double value) { | |
| 1507 | assert(validFloatRegister(regNum)); | |
| 1508 | _vectorScalarRegisters[regNum - UNW_PPC64_F0].asfloat.f = value; | |
| 1509 | } | |
| 1510 | ||
| 1511 | inline bool Registers_ppc64::validVectorRegister(int regNum) const { | |
| 1512 | #ifdef PPC64_HAS_VMX | |
| 1513 | if (regNum >= UNW_PPC64_VS0 && regNum <= UNW_PPC64_VS31) | |
| 1514 | return true; | |
| 1515 | if (regNum >= UNW_PPC64_VS32 && regNum <= UNW_PPC64_VS63) | |
| 1516 | return true; | |
| 1517 | #else | |
| 1518 | if (regNum >= UNW_PPC64_V0 && regNum <= UNW_PPC64_V31) | |
| 1519 | return true; | |
| 1520 | #endif | |
| 1521 | return false; | |
| 1522 | } | |
| 1523 | ||
| 1524 | inline int Registers_ppc64::getVectorRegNum(int num) | |
| 1525 | { | |
| 1526 | if (num >= UNW_PPC64_VS0 && num <= UNW_PPC64_VS31) | |
| 1527 | return num - UNW_PPC64_VS0; | |
| 1528 | else | |
| 1529 | return num - UNW_PPC64_VS32 + 32; | |
| 1530 | } | |
| 1531 | ||
| 1532 | inline v128 Registers_ppc64::getVectorRegister(int regNum) const { | |
| 1533 | assert(validVectorRegister(regNum)); | |
| 1534 | return _vectorScalarRegisters[getVectorRegNum(regNum)].v; | |
| 1535 | } | |
| 1536 | ||
| 1537 | inline void Registers_ppc64::setVectorRegister(int regNum, v128 value) { | |
| 1538 | assert(validVectorRegister(regNum)); | |
| 1539 | _vectorScalarRegisters[getVectorRegNum(regNum)].v = value; | |
| 1540 | } | |
| 1541 | ||
| 1542 | inline const char *Registers_ppc64::getRegisterName(int regNum) { | |
| 1543 | switch (regNum) { | |
| 1544 | case UNW_REG_IP: | |
| 1545 | return "ip"; | |
| 1546 | case UNW_REG_SP: | |
| 1547 | return "sp"; | |
| 1548 | case UNW_PPC64_R0: | |
| 1549 | return "r0"; | |
| 1550 | case UNW_PPC64_R1: | |
| 1551 | return "r1"; | |
| 1552 | case UNW_PPC64_R2: | |
| 1553 | return "r2"; | |
| 1554 | case UNW_PPC64_R3: | |
| 1555 | return "r3"; | |
| 1556 | case UNW_PPC64_R4: | |
| 1557 | return "r4"; | |
| 1558 | case UNW_PPC64_R5: | |
| 1559 | return "r5"; | |
| 1560 | case UNW_PPC64_R6: | |
| 1561 | return "r6"; | |
| 1562 | case UNW_PPC64_R7: | |
| 1563 | return "r7"; | |
| 1564 | case UNW_PPC64_R8: | |
| 1565 | return "r8"; | |
| 1566 | case UNW_PPC64_R9: | |
| 1567 | return "r9"; | |
| 1568 | case UNW_PPC64_R10: | |
| 1569 | return "r10"; | |
| 1570 | case UNW_PPC64_R11: | |
| 1571 | return "r11"; | |
| 1572 | case UNW_PPC64_R12: | |
| 1573 | return "r12"; | |
| 1574 | case UNW_PPC64_R13: | |
| 1575 | return "r13"; | |
| 1576 | case UNW_PPC64_R14: | |
| 1577 | return "r14"; | |
| 1578 | case UNW_PPC64_R15: | |
| 1579 | return "r15"; | |
| 1580 | case UNW_PPC64_R16: | |
| 1581 | return "r16"; | |
| 1582 | case UNW_PPC64_R17: | |
| 1583 | return "r17"; | |
| 1584 | case UNW_PPC64_R18: | |
| 1585 | return "r18"; | |
| 1586 | case UNW_PPC64_R19: | |
| 1587 | return "r19"; | |
| 1588 | case UNW_PPC64_R20: | |
| 1589 | return "r20"; | |
| 1590 | case UNW_PPC64_R21: | |
| 1591 | return "r21"; | |
| 1592 | case UNW_PPC64_R22: | |
| 1593 | return "r22"; | |
| 1594 | case UNW_PPC64_R23: | |
| 1595 | return "r23"; | |
| 1596 | case UNW_PPC64_R24: | |
| 1597 | return "r24"; | |
| 1598 | case UNW_PPC64_R25: | |
| 1599 | return "r25"; | |
| 1600 | case UNW_PPC64_R26: | |
| 1601 | return "r26"; | |
| 1602 | case UNW_PPC64_R27: | |
| 1603 | return "r27"; | |
| 1604 | case UNW_PPC64_R28: | |
| 1605 | return "r28"; | |
| 1606 | case UNW_PPC64_R29: | |
| 1607 | return "r29"; | |
| 1608 | case UNW_PPC64_R30: | |
| 1609 | return "r30"; | |
| 1610 | case UNW_PPC64_R31: | |
| 1611 | return "r31"; | |
| 1612 | case UNW_PPC64_CR0: | |
| 1613 | return "cr0"; | |
| 1614 | case UNW_PPC64_CR1: | |
| 1615 | return "cr1"; | |
| 1616 | case UNW_PPC64_CR2: | |
| 1617 | return "cr2"; | |
| 1618 | case UNW_PPC64_CR3: | |
| 1619 | return "cr3"; | |
| 1620 | case UNW_PPC64_CR4: | |
| 1621 | return "cr4"; | |
| 1622 | case UNW_PPC64_CR5: | |
| 1623 | return "cr5"; | |
| 1624 | case UNW_PPC64_CR6: | |
| 1625 | return "cr6"; | |
| 1626 | case UNW_PPC64_CR7: | |
| 1627 | return "cr7"; | |
| 1628 | case UNW_PPC64_XER: | |
| 1629 | return "xer"; | |
| 1630 | case UNW_PPC64_LR: | |
| 1631 | return "lr"; | |
| 1632 | case UNW_PPC64_CTR: | |
| 1633 | return "ctr"; | |
| 1634 | case UNW_PPC64_VRSAVE: | |
| 1635 | return "vrsave"; | |
| 1636 | case UNW_PPC64_F0: | |
| 1637 | return "fp0"; | |
| 1638 | case UNW_PPC64_F1: | |
| 1639 | return "fp1"; | |
| 1640 | case UNW_PPC64_F2: | |
| 1641 | return "fp2"; | |
| 1642 | case UNW_PPC64_F3: | |
| 1643 | return "fp3"; | |
| 1644 | case UNW_PPC64_F4: | |
| 1645 | return "fp4"; | |
| 1646 | case UNW_PPC64_F5: | |
| 1647 | return "fp5"; | |
| 1648 | case UNW_PPC64_F6: | |
| 1649 | return "fp6"; | |
| 1650 | case UNW_PPC64_F7: | |
| 1651 | return "fp7"; | |
| 1652 | case UNW_PPC64_F8: | |
| 1653 | return "fp8"; | |
| 1654 | case UNW_PPC64_F9: | |
| 1655 | return "fp9"; | |
| 1656 | case UNW_PPC64_F10: | |
| 1657 | return "fp10"; | |
| 1658 | case UNW_PPC64_F11: | |
| 1659 | return "fp11"; | |
| 1660 | case UNW_PPC64_F12: | |
| 1661 | return "fp12"; | |
| 1662 | case UNW_PPC64_F13: | |
| 1663 | return "fp13"; | |
| 1664 | case UNW_PPC64_F14: | |
| 1665 | return "fp14"; | |
| 1666 | case UNW_PPC64_F15: | |
| 1667 | return "fp15"; | |
| 1668 | case UNW_PPC64_F16: | |
| 1669 | return "fp16"; | |
| 1670 | case UNW_PPC64_F17: | |
| 1671 | return "fp17"; | |
| 1672 | case UNW_PPC64_F18: | |
| 1673 | return "fp18"; | |
| 1674 | case UNW_PPC64_F19: | |
| 1675 | return "fp19"; | |
| 1676 | case UNW_PPC64_F20: | |
| 1677 | return "fp20"; | |
| 1678 | case UNW_PPC64_F21: | |
| 1679 | return "fp21"; | |
| 1680 | case UNW_PPC64_F22: | |
| 1681 | return "fp22"; | |
| 1682 | case UNW_PPC64_F23: | |
| 1683 | return "fp23"; | |
| 1684 | case UNW_PPC64_F24: | |
| 1685 | return "fp24"; | |
| 1686 | case UNW_PPC64_F25: | |
| 1687 | return "fp25"; | |
| 1688 | case UNW_PPC64_F26: | |
| 1689 | return "fp26"; | |
| 1690 | case UNW_PPC64_F27: | |
| 1691 | return "fp27"; | |
| 1692 | case UNW_PPC64_F28: | |
| 1693 | return "fp28"; | |
| 1694 | case UNW_PPC64_F29: | |
| 1695 | return "fp29"; | |
| 1696 | case UNW_PPC64_F30: | |
| 1697 | return "fp30"; | |
| 1698 | case UNW_PPC64_F31: | |
| 1699 | return "fp31"; | |
| 1700 | case UNW_PPC64_V0: | |
| 1701 | return "v0"; | |
| 1702 | case UNW_PPC64_V1: | |
| 1703 | return "v1"; | |
| 1704 | case UNW_PPC64_V2: | |
| 1705 | return "v2"; | |
| 1706 | case UNW_PPC64_V3: | |
| 1707 | return "v3"; | |
| 1708 | case UNW_PPC64_V4: | |
| 1709 | return "v4"; | |
| 1710 | case UNW_PPC64_V5: | |
| 1711 | return "v5"; | |
| 1712 | case UNW_PPC64_V6: | |
| 1713 | return "v6"; | |
| 1714 | case UNW_PPC64_V7: | |
| 1715 | return "v7"; | |
| 1716 | case UNW_PPC64_V8: | |
| 1717 | return "v8"; | |
| 1718 | case UNW_PPC64_V9: | |
| 1719 | return "v9"; | |
| 1720 | case UNW_PPC64_V10: | |
| 1721 | return "v10"; | |
| 1722 | case UNW_PPC64_V11: | |
| 1723 | return "v11"; | |
| 1724 | case UNW_PPC64_V12: | |
| 1725 | return "v12"; | |
| 1726 | case UNW_PPC64_V13: | |
| 1727 | return "v13"; | |
| 1728 | case UNW_PPC64_V14: | |
| 1729 | return "v14"; | |
| 1730 | case UNW_PPC64_V15: | |
| 1731 | return "v15"; | |
| 1732 | case UNW_PPC64_V16: | |
| 1733 | return "v16"; | |
| 1734 | case UNW_PPC64_V17: | |
| 1735 | return "v17"; | |
| 1736 | case UNW_PPC64_V18: | |
| 1737 | return "v18"; | |
| 1738 | case UNW_PPC64_V19: | |
| 1739 | return "v19"; | |
| 1740 | case UNW_PPC64_V20: | |
| 1741 | return "v20"; | |
| 1742 | case UNW_PPC64_V21: | |
| 1743 | return "v21"; | |
| 1744 | case UNW_PPC64_V22: | |
| 1745 | return "v22"; | |
| 1746 | case UNW_PPC64_V23: | |
| 1747 | return "v23"; | |
| 1748 | case UNW_PPC64_V24: | |
| 1749 | return "v24"; | |
| 1750 | case UNW_PPC64_V25: | |
| 1751 | return "v25"; | |
| 1752 | case UNW_PPC64_V26: | |
| 1753 | return "v26"; | |
| 1754 | case UNW_PPC64_V27: | |
| 1755 | return "v27"; | |
| 1756 | case UNW_PPC64_V28: | |
| 1757 | return "v28"; | |
| 1758 | case UNW_PPC64_V29: | |
| 1759 | return "v29"; | |
| 1760 | case UNW_PPC64_V30: | |
| 1761 | return "v30"; | |
| 1762 | case UNW_PPC64_V31: | |
| 1763 | return "v31"; | |
| 1764 | } | |
| 1765 | return "unknown register"; | |
| 1766 | } | |
| 1767 | #endif // _LIBUNWIND_TARGET_PPC64 | |
| 1768 | ||
| 1769 | ||
| 1770 | #if defined(_LIBUNWIND_TARGET_AARCH64) | |
| 1771 | /// Registers_arm64 holds the register state of a thread in a 64-bit arm | |
| 1772 | /// process. | |
| 1773 | class _LIBUNWIND_HIDDEN Registers_arm64 { | |
| 1774 | public: | |
| 1775 | Registers_arm64(); | |
| 1776 | Registers_arm64(const void *registers); | |
| 1777 | ||
| 1778 | bool validRegister(int num) const; | |
| 1779 | uint64_t getRegister(int num) const; | |
| 1780 | void setRegister(int num, uint64_t value); | |
| 1781 | bool validFloatRegister(int num) const; | |
| 1782 | double getFloatRegister(int num) const; | |
| 1783 | void setFloatRegister(int num, double value); | |
| 1784 | bool validVectorRegister(int num) const; | |
| 1785 | v128 getVectorRegister(int num) const; | |
| 1786 | void setVectorRegister(int num, v128 value); | |
| 1787 | static const char *getRegisterName(int num); | |
| 1788 | void jumpto(); | |
| 1789 | static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64; } | |
| 1790 | static int getArch() { return REGISTERS_ARM64; } | |
| 1791 | ||
| 1792 | uint64_t getSP() const { return _registers.__sp; } | |
| 1793 | void setSP(uint64_t value) { _registers.__sp = value; } | |
| 1794 | uint64_t getIP() const { return _registers.__pc; } | |
| 1795 | void setIP(uint64_t value) { _registers.__pc = value; } | |
| 1796 | uint64_t getFP() const { return _registers.__fp; } | |
| 1797 | void setFP(uint64_t value) { _registers.__fp = value; } | |
| 1798 | ||
| 1799 | private: | |
| 1800 | struct GPRs { | |
| 1801 | uint64_t __x[29]; // x0-x28 | |
| 1802 | uint64_t __fp; // Frame pointer x29 | |
| 1803 | uint64_t __lr; // Link register x30 | |
| 1804 | uint64_t __sp; // Stack pointer x31 | |
| 1805 | uint64_t __pc; // Program counter | |
| 1806 | uint64_t __ra_sign_state; // RA sign state register | |
| 1807 | }; | |
| 1808 | ||
| 1809 | GPRs _registers; | |
| 1810 | double _vectorHalfRegisters[32]; | |
| 1811 | // Currently only the lower double in 128-bit vectore registers | |
| 1812 | // is perserved during unwinding. We could define new register | |
| 1813 | // numbers (> 96) which mean whole vector registers, then this | |
| 1814 | // struct would need to change to contain whole vector registers. | |
| 1815 | }; | |
| 1816 | ||
| 1817 | inline Registers_arm64::Registers_arm64(const void *registers) { | |
| 1818 | static_assert((check_fit<Registers_arm64, unw_context_t>::does_fit), | |
| 1819 | "arm64 registers do not fit into unw_context_t"); | |
| 1820 | memcpy(&_registers, registers, sizeof(_registers)); | |
| 1821 | static_assert(sizeof(GPRs) == 0x110, | |
| 1822 | "expected VFP registers to be at offset 272"); | |
| 1823 | memcpy(_vectorHalfRegisters, | |
| 1824 | static_cast<const uint8_t *>(registers) + sizeof(GPRs), | |
| 1825 | sizeof(_vectorHalfRegisters)); | |
| 1826 | } | |
| 1827 | ||
| 1828 | inline Registers_arm64::Registers_arm64() { | |
| 1829 | memset(&_registers, 0, sizeof(_registers)); | |
| 1830 | memset(&_vectorHalfRegisters, 0, sizeof(_vectorHalfRegisters)); | |
| 1831 | } | |
| 1832 | ||
| 1833 | inline bool Registers_arm64::validRegister(int regNum) const { | |
| 1834 | if (regNum == UNW_REG_IP) | |
| 1835 | return true; | |
| 1836 | if (regNum == UNW_REG_SP) | |
| 1837 | return true; | |
| 1838 | if (regNum < 0) | |
| 1839 | return false; | |
| 1840 | if (regNum > 95) | |
| 1841 | return false; | |
| 1842 | if (regNum == UNW_ARM64_RA_SIGN_STATE) | |
| 1843 | return true; | |
| 1844 | if ((regNum > 31) && (regNum < 64)) | |
| 1845 | return false; | |
| 1846 | return true; | |
| 1847 | } | |
| 1848 | ||
| 1849 | inline uint64_t Registers_arm64::getRegister(int regNum) const { | |
| 1850 | if (regNum == UNW_REG_IP) | |
| 1851 | return _registers.__pc; | |
| 1852 | if (regNum == UNW_REG_SP) | |
| 1853 | return _registers.__sp; | |
| 1854 | if (regNum == UNW_ARM64_RA_SIGN_STATE) | |
| 1855 | return _registers.__ra_sign_state; | |
| 1856 | if ((regNum >= 0) && (regNum < 32)) | |
| 1857 | return _registers.__x[regNum]; | |
| 1858 | _LIBUNWIND_ABORT("unsupported arm64 register"); | |
| 1859 | } | |
| 1860 | ||
| 1861 | inline void Registers_arm64::setRegister(int regNum, uint64_t value) { | |
| 1862 | if (regNum == UNW_REG_IP) | |
| 1863 | _registers.__pc = value; | |
| 1864 | else if (regNum == UNW_REG_SP) | |
| 1865 | _registers.__sp = value; | |
| 1866 | else if (regNum == UNW_ARM64_RA_SIGN_STATE) | |
| 1867 | _registers.__ra_sign_state = value; | |
| 1868 | else if ((regNum >= 0) && (regNum < 32)) | |
| 1869 | _registers.__x[regNum] = value; | |
| 1870 | else | |
| 1871 | _LIBUNWIND_ABORT("unsupported arm64 register"); | |
| 1872 | } | |
| 1873 | ||
| 1874 | inline const char *Registers_arm64::getRegisterName(int regNum) { | |
| 1875 | switch (regNum) { | |
| 1876 | case UNW_REG_IP: | |
| 1877 | return "pc"; | |
| 1878 | case UNW_REG_SP: | |
| 1879 | return "sp"; | |
| 1880 | case UNW_ARM64_X0: | |
| 1881 | return "x0"; | |
| 1882 | case UNW_ARM64_X1: | |
| 1883 | return "x1"; | |
| 1884 | case UNW_ARM64_X2: | |
| 1885 | return "x2"; | |
| 1886 | case UNW_ARM64_X3: | |
| 1887 | return "x3"; | |
| 1888 | case UNW_ARM64_X4: | |
| 1889 | return "x4"; | |
| 1890 | case UNW_ARM64_X5: | |
| 1891 | return "x5"; | |
| 1892 | case UNW_ARM64_X6: | |
| 1893 | return "x6"; | |
| 1894 | case UNW_ARM64_X7: | |
| 1895 | return "x7"; | |
| 1896 | case UNW_ARM64_X8: | |
| 1897 | return "x8"; | |
| 1898 | case UNW_ARM64_X9: | |
| 1899 | return "x9"; | |
| 1900 | case UNW_ARM64_X10: | |
| 1901 | return "x10"; | |
| 1902 | case UNW_ARM64_X11: | |
| 1903 | return "x11"; | |
| 1904 | case UNW_ARM64_X12: | |
| 1905 | return "x12"; | |
| 1906 | case UNW_ARM64_X13: | |
| 1907 | return "x13"; | |
| 1908 | case UNW_ARM64_X14: | |
| 1909 | return "x14"; | |
| 1910 | case UNW_ARM64_X15: | |
| 1911 | return "x15"; | |
| 1912 | case UNW_ARM64_X16: | |
| 1913 | return "x16"; | |
| 1914 | case UNW_ARM64_X17: | |
| 1915 | return "x17"; | |
| 1916 | case UNW_ARM64_X18: | |
| 1917 | return "x18"; | |
| 1918 | case UNW_ARM64_X19: | |
| 1919 | return "x19"; | |
| 1920 | case UNW_ARM64_X20: | |
| 1921 | return "x20"; | |
| 1922 | case UNW_ARM64_X21: | |
| 1923 | return "x21"; | |
| 1924 | case UNW_ARM64_X22: | |
| 1925 | return "x22"; | |
| 1926 | case UNW_ARM64_X23: | |
| 1927 | return "x23"; | |
| 1928 | case UNW_ARM64_X24: | |
| 1929 | return "x24"; | |
| 1930 | case UNW_ARM64_X25: | |
| 1931 | return "x25"; | |
| 1932 | case UNW_ARM64_X26: | |
| 1933 | return "x26"; | |
| 1934 | case UNW_ARM64_X27: | |
| 1935 | return "x27"; | |
| 1936 | case UNW_ARM64_X28: | |
| 1937 | return "x28"; | |
| 1938 | case UNW_ARM64_X29: | |
| 1939 | return "fp"; | |
| 1940 | case UNW_ARM64_X30: | |
| 1941 | return "lr"; | |
| 1942 | case UNW_ARM64_X31: | |
| 1943 | return "sp"; | |
| 1944 | case UNW_ARM64_D0: | |
| 1945 | return "d0"; | |
| 1946 | case UNW_ARM64_D1: | |
| 1947 | return "d1"; | |
| 1948 | case UNW_ARM64_D2: | |
| 1949 | return "d2"; | |
| 1950 | case UNW_ARM64_D3: | |
| 1951 | return "d3"; | |
| 1952 | case UNW_ARM64_D4: | |
| 1953 | return "d4"; | |
| 1954 | case UNW_ARM64_D5: | |
| 1955 | return "d5"; | |
| 1956 | case UNW_ARM64_D6: | |
| 1957 | return "d6"; | |
| 1958 | case UNW_ARM64_D7: | |
| 1959 | return "d7"; | |
| 1960 | case UNW_ARM64_D8: | |
| 1961 | return "d8"; | |
| 1962 | case UNW_ARM64_D9: | |
| 1963 | return "d9"; | |
| 1964 | case UNW_ARM64_D10: | |
| 1965 | return "d10"; | |
| 1966 | case UNW_ARM64_D11: | |
| 1967 | return "d11"; | |
| 1968 | case UNW_ARM64_D12: | |
| 1969 | return "d12"; | |
| 1970 | case UNW_ARM64_D13: | |
| 1971 | return "d13"; | |
| 1972 | case UNW_ARM64_D14: | |
| 1973 | return "d14"; | |
| 1974 | case UNW_ARM64_D15: | |
| 1975 | return "d15"; | |
| 1976 | case UNW_ARM64_D16: | |
| 1977 | return "d16"; | |
| 1978 | case UNW_ARM64_D17: | |
| 1979 | return "d17"; | |
| 1980 | case UNW_ARM64_D18: | |
| 1981 | return "d18"; | |
| 1982 | case UNW_ARM64_D19: | |
| 1983 | return "d19"; | |
| 1984 | case UNW_ARM64_D20: | |
| 1985 | return "d20"; | |
| 1986 | case UNW_ARM64_D21: | |
| 1987 | return "d21"; | |
| 1988 | case UNW_ARM64_D22: | |
| 1989 | return "d22"; | |
| 1990 | case UNW_ARM64_D23: | |
| 1991 | return "d23"; | |
| 1992 | case UNW_ARM64_D24: | |
| 1993 | return "d24"; | |
| 1994 | case UNW_ARM64_D25: | |
| 1995 | return "d25"; | |
| 1996 | case UNW_ARM64_D26: | |
| 1997 | return "d26"; | |
| 1998 | case UNW_ARM64_D27: | |
| 1999 | return "d27"; | |
| 2000 | case UNW_ARM64_D28: | |
| 2001 | return "d28"; | |
| 2002 | case UNW_ARM64_D29: | |
| 2003 | return "d29"; | |
| 2004 | case UNW_ARM64_D30: | |
| 2005 | return "d30"; | |
| 2006 | case UNW_ARM64_D31: | |
| 2007 | return "d31"; | |
| 2008 | default: | |
| 2009 | return "unknown register"; | |
| 2010 | } | |
| 2011 | } | |
| 2012 | ||
| 2013 | inline bool Registers_arm64::validFloatRegister(int regNum) const { | |
| 2014 | if (regNum < UNW_ARM64_D0) | |
| 2015 | return false; | |
| 2016 | if (regNum > UNW_ARM64_D31) | |
| 2017 | return false; | |
| 2018 | return true; | |
| 2019 | } | |
| 2020 | ||
| 2021 | inline double Registers_arm64::getFloatRegister(int regNum) const { | |
| 2022 | assert(validFloatRegister(regNum)); | |
| 2023 | return _vectorHalfRegisters[regNum - UNW_ARM64_D0]; | |
| 2024 | } | |
| 2025 | ||
| 2026 | inline void Registers_arm64::setFloatRegister(int regNum, double value) { | |
| 2027 | assert(validFloatRegister(regNum)); | |
| 2028 | _vectorHalfRegisters[regNum - UNW_ARM64_D0] = value; | |
| 2029 | } | |
| 2030 | ||
| 2031 | inline bool Registers_arm64::validVectorRegister(int) const { | |
| 2032 | return false; | |
| 2033 | } | |
| 2034 | ||
| 2035 | inline v128 Registers_arm64::getVectorRegister(int) const { | |
| 2036 | _LIBUNWIND_ABORT("no arm64 vector register support yet"); | |
| 2037 | } | |
| 2038 | ||
| 2039 | inline void Registers_arm64::setVectorRegister(int, v128) { | |
| 2040 | _LIBUNWIND_ABORT("no arm64 vector register support yet"); | |
| 2041 | } | |
| 2042 | #endif // _LIBUNWIND_TARGET_AARCH64 | |
| 2043 | ||
| 2044 | #if defined(_LIBUNWIND_TARGET_ARM) | |
| 2045 | /// Registers_arm holds the register state of a thread in a 32-bit arm | |
| 2046 | /// process. | |
| 2047 | /// | |
| 2048 | /// NOTE: Assumes VFPv3. On ARM processors without a floating point unit, | |
| 2049 | /// this uses more memory than required. | |
| 2050 | class _LIBUNWIND_HIDDEN Registers_arm { | |
| 2051 | public: | |
| 2052 | Registers_arm(); | |
| 2053 | Registers_arm(const void *registers); | |
| 2054 | ||
| 2055 | bool validRegister(int num) const; | |
| 2056 | uint32_t getRegister(int num) const; | |
| 2057 | void setRegister(int num, uint32_t value); | |
| 2058 | bool validFloatRegister(int num) const; | |
| 2059 | unw_fpreg_t getFloatRegister(int num); | |
| 2060 | void setFloatRegister(int num, unw_fpreg_t value); | |
| 2061 | bool validVectorRegister(int num) const; | |
| 2062 | v128 getVectorRegister(int num) const; | |
| 2063 | void setVectorRegister(int num, v128 value); | |
| 2064 | static const char *getRegisterName(int num); | |
| 2065 | void jumpto() { | |
| 2066 | restoreSavedFloatRegisters(); | |
| 2067 | restoreCoreAndJumpTo(); | |
| 2068 | } | |
| 2069 | static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM; } | |
| 2070 | static int getArch() { return REGISTERS_ARM; } | |
| 2071 | ||
| 2072 | uint32_t getSP() const { return _registers.__sp; } | |
| 2073 | void setSP(uint32_t value) { _registers.__sp = value; } | |
| 2074 | uint32_t getIP() const { return _registers.__pc; } | |
| 2075 | void setIP(uint32_t value) { _registers.__pc = value; } | |
| 2076 | ||
| 2077 | void saveVFPAsX() { | |
| 2078 | assert(_use_X_for_vfp_save || !_saved_vfp_d0_d15); | |
| 2079 | _use_X_for_vfp_save = true; | |
| 2080 | } | |
| 2081 | ||
| 2082 | void restoreSavedFloatRegisters() { | |
| 2083 | if (_saved_vfp_d0_d15) { | |
| 2084 | if (_use_X_for_vfp_save) | |
| 2085 | restoreVFPWithFLDMX(_vfp_d0_d15_pad); | |
| 2086 | else | |
| 2087 | restoreVFPWithFLDMD(_vfp_d0_d15_pad); | |
| 2088 | } | |
| 2089 | if (_saved_vfp_d16_d31) | |
| 2090 | restoreVFPv3(_vfp_d16_d31); | |
| 2091 | #if defined(__ARM_WMMX) | |
| 2092 | if (_saved_iwmmx) | |
| 2093 | restoreiWMMX(_iwmmx); | |
| 2094 | if (_saved_iwmmx_control) | |
| 2095 | restoreiWMMXControl(_iwmmx_control); | |
| 2096 | #endif | |
| 2097 | } | |
| 2098 | ||
| 2099 | private: | |
| 2100 | struct GPRs { | |
| 2101 | uint32_t __r[13]; // r0-r12 | |
| 2102 | uint32_t __sp; // Stack pointer r13 | |
| 2103 | uint32_t __lr; // Link register r14 | |
| 2104 | uint32_t __pc; // Program counter r15 | |
| 2105 | }; | |
| 2106 | ||
| 2107 | static void saveVFPWithFSTMD(unw_fpreg_t*); | |
| 2108 | static void saveVFPWithFSTMX(unw_fpreg_t*); | |
| 2109 | static void saveVFPv3(unw_fpreg_t*); | |
| 2110 | static void restoreVFPWithFLDMD(unw_fpreg_t*); | |
| 2111 | static void restoreVFPWithFLDMX(unw_fpreg_t*); | |
| 2112 | static void restoreVFPv3(unw_fpreg_t*); | |
| 2113 | #if defined(__ARM_WMMX) | |
| 2114 | static void saveiWMMX(unw_fpreg_t*); | |
| 2115 | static void saveiWMMXControl(uint32_t*); | |
| 2116 | static void restoreiWMMX(unw_fpreg_t*); | |
| 2117 | static void restoreiWMMXControl(uint32_t*); | |
| 2118 | #endif | |
| 2119 | void restoreCoreAndJumpTo(); | |
| 2120 | ||
| 2121 | // ARM registers | |
| 2122 | GPRs _registers; | |
| 2123 | ||
| 2124 | // We save floating point registers lazily because we can't know ahead of | |
| 2125 | // time which ones are used. See EHABI #4.7. | |
| 2126 | ||
| 2127 | // Whether D0-D15 are saved in the FTSMX instead of FSTMD format. | |
| 2128 | // | |
| 2129 | // See EHABI #7.5 that explains how matching instruction sequences for load | |
| 2130 | // and store need to be used to correctly restore the exact register bits. | |
| 2131 | bool _use_X_for_vfp_save; | |
| 2132 | // Whether VFP D0-D15 are saved. | |
| 2133 | bool _saved_vfp_d0_d15; | |
| 2134 | // Whether VFPv3 D16-D31 are saved. | |
| 2135 | bool _saved_vfp_d16_d31; | |
| 2136 | // VFP registers D0-D15, + padding if saved using FSTMX | |
| 2137 | unw_fpreg_t _vfp_d0_d15_pad[17]; | |
| 2138 | // VFPv3 registers D16-D31, always saved using FSTMD | |
| 2139 | unw_fpreg_t _vfp_d16_d31[16]; | |
| 2140 | #if defined(__ARM_WMMX) | |
| 2141 | // Whether iWMMX data registers are saved. | |
| 2142 | bool _saved_iwmmx; | |
| 2143 | // Whether iWMMX control registers are saved. | |
| 2144 | mutable bool _saved_iwmmx_control; | |
| 2145 | // iWMMX registers | |
| 2146 | unw_fpreg_t _iwmmx[16]; | |
| 2147 | // iWMMX control registers | |
| 2148 | mutable uint32_t _iwmmx_control[4]; | |
| 2149 | #endif | |
| 2150 | }; | |
| 2151 | ||
| 2152 | inline Registers_arm::Registers_arm(const void *registers) | |
| 2153 | : _use_X_for_vfp_save(false), | |
| 2154 | _saved_vfp_d0_d15(false), | |
| 2155 | _saved_vfp_d16_d31(false) { | |
| 2156 | static_assert((check_fit<Registers_arm, unw_context_t>::does_fit), | |
| 2157 | "arm registers do not fit into unw_context_t"); | |
| 2158 | // See unw_getcontext() note about data. | |
| 2159 | memcpy(&_registers, registers, sizeof(_registers)); | |
| 2160 | memset(&_vfp_d0_d15_pad, 0, sizeof(_vfp_d0_d15_pad)); | |
| 2161 | memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31)); | |
| 2162 | #if defined(__ARM_WMMX) | |
| 2163 | _saved_iwmmx = false; | |
| 2164 | _saved_iwmmx_control = false; | |
| 2165 | memset(&_iwmmx, 0, sizeof(_iwmmx)); | |
| 2166 | memset(&_iwmmx_control, 0, sizeof(_iwmmx_control)); | |
| 2167 | #endif | |
| 2168 | } | |
| 2169 | ||
| 2170 | inline Registers_arm::Registers_arm() | |
| 2171 | : _use_X_for_vfp_save(false), | |
| 2172 | _saved_vfp_d0_d15(false), | |
| 2173 | _saved_vfp_d16_d31(false) { | |
| 2174 | memset(&_registers, 0, sizeof(_registers)); | |
| 2175 | memset(&_vfp_d0_d15_pad, 0, sizeof(_vfp_d0_d15_pad)); | |
| 2176 | memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31)); | |
| 2177 | #if defined(__ARM_WMMX) | |
| 2178 | _saved_iwmmx = false; | |
| 2179 | _saved_iwmmx_control = false; | |
| 2180 | memset(&_iwmmx, 0, sizeof(_iwmmx)); | |
| 2181 | memset(&_iwmmx_control, 0, sizeof(_iwmmx_control)); | |
| 2182 | #endif | |
| 2183 | } | |
| 2184 | ||
| 2185 | inline bool Registers_arm::validRegister(int regNum) const { | |
| 2186 | // Returns true for all non-VFP registers supported by the EHABI | |
| 2187 | // virtual register set (VRS). | |
| 2188 | if (regNum == UNW_REG_IP) | |
| 2189 | return true; | |
| 2190 | ||
| 2191 | if (regNum == UNW_REG_SP) | |
| 2192 | return true; | |
| 2193 | ||
| 2194 | if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R15) | |
| 2195 | return true; | |
| 2196 | ||
| 2197 | #if defined(__ARM_WMMX) | |
| 2198 | if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) | |
| 2199 | return true; | |
| 2200 | #endif | |
| 2201 | ||
| 2202 | return false; | |
| 2203 | } | |
| 2204 | ||
| 2205 | inline uint32_t Registers_arm::getRegister(int regNum) const { | |
| 2206 | if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP) | |
| 2207 | return _registers.__sp; | |
| 2208 | ||
| 2209 | if (regNum == UNW_ARM_LR) | |
| 2210 | return _registers.__lr; | |
| 2211 | ||
| 2212 | if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP) | |
| 2213 | return _registers.__pc; | |
| 2214 | ||
| 2215 | if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R12) | |
| 2216 | return _registers.__r[regNum]; | |
| 2217 | ||
| 2218 | #if defined(__ARM_WMMX) | |
| 2219 | if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) { | |
| 2220 | if (!_saved_iwmmx_control) { | |
| 2221 | _saved_iwmmx_control = true; | |
| 2222 | saveiWMMXControl(_iwmmx_control); | |
| 2223 | } | |
| 2224 | return _iwmmx_control[regNum - UNW_ARM_WC0]; | |
| 2225 | } | |
| 2226 | #endif | |
| 2227 | ||
| 2228 | _LIBUNWIND_ABORT("unsupported arm register"); | |
| 2229 | } | |
| 2230 | ||
| 2231 | inline void Registers_arm::setRegister(int regNum, uint32_t value) { | |
| 2232 | if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP) { | |
| 2233 | _registers.__sp = value; | |
| 2234 | return; | |
| 2235 | } | |
| 2236 | ||
| 2237 | if (regNum == UNW_ARM_LR) { | |
| 2238 | _registers.__lr = value; | |
| 2239 | return; | |
| 2240 | } | |
| 2241 | ||
| 2242 | if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP) { | |
| 2243 | _registers.__pc = value; | |
| 2244 | return; | |
| 2245 | } | |
| 2246 | ||
| 2247 | if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R12) { | |
| 2248 | _registers.__r[regNum] = value; | |
| 2249 | return; | |
| 2250 | } | |
| 2251 | ||
| 2252 | #if defined(__ARM_WMMX) | |
| 2253 | if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) { | |
| 2254 | if (!_saved_iwmmx_control) { | |
| 2255 | _saved_iwmmx_control = true; | |
| 2256 | saveiWMMXControl(_iwmmx_control); | |
| 2257 | } | |
| 2258 | _iwmmx_control[regNum - UNW_ARM_WC0] = value; | |
| 2259 | return; | |
| 2260 | } | |
| 2261 | #endif | |
| 2262 | ||
| 2263 | _LIBUNWIND_ABORT("unsupported arm register"); | |
| 2264 | } | |
| 2265 | ||
| 2266 | inline const char *Registers_arm::getRegisterName(int regNum) { | |
| 2267 | switch (regNum) { | |
| 2268 | case UNW_REG_IP: | |
| 2269 | case UNW_ARM_IP: // UNW_ARM_R15 is alias | |
| 2270 | return "pc"; | |
| 2271 | case UNW_ARM_LR: // UNW_ARM_R14 is alias | |
| 2272 | return "lr"; | |
| 2273 | case UNW_REG_SP: | |
| 2274 | case UNW_ARM_SP: // UNW_ARM_R13 is alias | |
| 2275 | return "sp"; | |
| 2276 | case UNW_ARM_R0: | |
| 2277 | return "r0"; | |
| 2278 | case UNW_ARM_R1: | |
| 2279 | return "r1"; | |
| 2280 | case UNW_ARM_R2: | |
| 2281 | return "r2"; | |
| 2282 | case UNW_ARM_R3: | |
| 2283 | return "r3"; | |
| 2284 | case UNW_ARM_R4: | |
| 2285 | return "r4"; | |
| 2286 | case UNW_ARM_R5: | |
| 2287 | return "r5"; | |
| 2288 | case UNW_ARM_R6: | |
| 2289 | return "r6"; | |
| 2290 | case UNW_ARM_R7: | |
| 2291 | return "r7"; | |
| 2292 | case UNW_ARM_R8: | |
| 2293 | return "r8"; | |
| 2294 | case UNW_ARM_R9: | |
| 2295 | return "r9"; | |
| 2296 | case UNW_ARM_R10: | |
| 2297 | return "r10"; | |
| 2298 | case UNW_ARM_R11: | |
| 2299 | return "r11"; | |
| 2300 | case UNW_ARM_R12: | |
| 2301 | return "r12"; | |
| 2302 | case UNW_ARM_S0: | |
| 2303 | return "s0"; | |
| 2304 | case UNW_ARM_S1: | |
| 2305 | return "s1"; | |
| 2306 | case UNW_ARM_S2: | |
| 2307 | return "s2"; | |
| 2308 | case UNW_ARM_S3: | |
| 2309 | return "s3"; | |
| 2310 | case UNW_ARM_S4: | |
| 2311 | return "s4"; | |
| 2312 | case UNW_ARM_S5: | |
| 2313 | return "s5"; | |
| 2314 | case UNW_ARM_S6: | |
| 2315 | return "s6"; | |
| 2316 | case UNW_ARM_S7: | |
| 2317 | return "s7"; | |
| 2318 | case UNW_ARM_S8: | |
| 2319 | return "s8"; | |
| 2320 | case UNW_ARM_S9: | |
| 2321 | return "s9"; | |
| 2322 | case UNW_ARM_S10: | |
| 2323 | return "s10"; | |
| 2324 | case UNW_ARM_S11: | |
| 2325 | return "s11"; | |
| 2326 | case UNW_ARM_S12: | |
| 2327 | return "s12"; | |
| 2328 | case UNW_ARM_S13: | |
| 2329 | return "s13"; | |
| 2330 | case UNW_ARM_S14: | |
| 2331 | return "s14"; | |
| 2332 | case UNW_ARM_S15: | |
| 2333 | return "s15"; | |
| 2334 | case UNW_ARM_S16: | |
| 2335 | return "s16"; | |
| 2336 | case UNW_ARM_S17: | |
| 2337 | return "s17"; | |
| 2338 | case UNW_ARM_S18: | |
| 2339 | return "s18"; | |
| 2340 | case UNW_ARM_S19: | |
| 2341 | return "s19"; | |
| 2342 | case UNW_ARM_S20: | |
| 2343 | return "s20"; | |
| 2344 | case UNW_ARM_S21: | |
| 2345 | return "s21"; | |
| 2346 | case UNW_ARM_S22: | |
| 2347 | return "s22"; | |
| 2348 | case UNW_ARM_S23: | |
| 2349 | return "s23"; | |
| 2350 | case UNW_ARM_S24: | |
| 2351 | return "s24"; | |
| 2352 | case UNW_ARM_S25: | |
| 2353 | return "s25"; | |
| 2354 | case UNW_ARM_S26: | |
| 2355 | return "s26"; | |
| 2356 | case UNW_ARM_S27: | |
| 2357 | return "s27"; | |
| 2358 | case UNW_ARM_S28: | |
| 2359 | return "s28"; | |
| 2360 | case UNW_ARM_S29: | |
| 2361 | return "s29"; | |
| 2362 | case UNW_ARM_S30: | |
| 2363 | return "s30"; | |
| 2364 | case UNW_ARM_S31: | |
| 2365 | return "s31"; | |
| 2366 | case UNW_ARM_D0: | |
| 2367 | return "d0"; | |
| 2368 | case UNW_ARM_D1: | |
| 2369 | return "d1"; | |
| 2370 | case UNW_ARM_D2: | |
| 2371 | return "d2"; | |
| 2372 | case UNW_ARM_D3: | |
| 2373 | return "d3"; | |
| 2374 | case UNW_ARM_D4: | |
| 2375 | return "d4"; | |
| 2376 | case UNW_ARM_D5: | |
| 2377 | return "d5"; | |
| 2378 | case UNW_ARM_D6: | |
| 2379 | return "d6"; | |
| 2380 | case UNW_ARM_D7: | |
| 2381 | return "d7"; | |
| 2382 | case UNW_ARM_D8: | |
| 2383 | return "d8"; | |
| 2384 | case UNW_ARM_D9: | |
| 2385 | return "d9"; | |
| 2386 | case UNW_ARM_D10: | |
| 2387 | return "d10"; | |
| 2388 | case UNW_ARM_D11: | |
| 2389 | return "d11"; | |
| 2390 | case UNW_ARM_D12: | |
| 2391 | return "d12"; | |
| 2392 | case UNW_ARM_D13: | |
| 2393 | return "d13"; | |
| 2394 | case UNW_ARM_D14: | |
| 2395 | return "d14"; | |
| 2396 | case UNW_ARM_D15: | |
| 2397 | return "d15"; | |
| 2398 | case UNW_ARM_D16: | |
| 2399 | return "d16"; | |
| 2400 | case UNW_ARM_D17: | |
| 2401 | return "d17"; | |
| 2402 | case UNW_ARM_D18: | |
| 2403 | return "d18"; | |
| 2404 | case UNW_ARM_D19: | |
| 2405 | return "d19"; | |
| 2406 | case UNW_ARM_D20: | |
| 2407 | return "d20"; | |
| 2408 | case UNW_ARM_D21: | |
| 2409 | return "d21"; | |
| 2410 | case UNW_ARM_D22: | |
| 2411 | return "d22"; | |
| 2412 | case UNW_ARM_D23: | |
| 2413 | return "d23"; | |
| 2414 | case UNW_ARM_D24: | |
| 2415 | return "d24"; | |
| 2416 | case UNW_ARM_D25: | |
| 2417 | return "d25"; | |
| 2418 | case UNW_ARM_D26: | |
| 2419 | return "d26"; | |
| 2420 | case UNW_ARM_D27: | |
| 2421 | return "d27"; | |
| 2422 | case UNW_ARM_D28: | |
| 2423 | return "d28"; | |
| 2424 | case UNW_ARM_D29: | |
| 2425 | return "d29"; | |
| 2426 | case UNW_ARM_D30: | |
| 2427 | return "d30"; | |
| 2428 | case UNW_ARM_D31: | |
| 2429 | return "d31"; | |
| 2430 | default: | |
| 2431 | return "unknown register"; | |
| 2432 | } | |
| 2433 | } | |
| 2434 | ||
| 2435 | inline bool Registers_arm::validFloatRegister(int regNum) const { | |
| 2436 | // NOTE: Consider the intel MMX registers floating points so the | |
| 2437 | // unw_get_fpreg can be used to transmit the 64-bit data back. | |
| 2438 | return ((regNum >= UNW_ARM_D0) && (regNum <= UNW_ARM_D31)) | |
| 2439 | #if defined(__ARM_WMMX) | |
| 2440 | || ((regNum >= UNW_ARM_WR0) && (regNum <= UNW_ARM_WR15)) | |
| 2441 | #endif | |
| 2442 | ; | |
| 2443 | } | |
| 2444 | ||
| 2445 | inline unw_fpreg_t Registers_arm::getFloatRegister(int regNum) { | |
| 2446 | if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D15) { | |
| 2447 | if (!_saved_vfp_d0_d15) { | |
| 2448 | _saved_vfp_d0_d15 = true; | |
| 2449 | if (_use_X_for_vfp_save) | |
| 2450 | saveVFPWithFSTMX(_vfp_d0_d15_pad); | |
| 2451 | else | |
| 2452 | saveVFPWithFSTMD(_vfp_d0_d15_pad); | |
| 2453 | } | |
| 2454 | return _vfp_d0_d15_pad[regNum - UNW_ARM_D0]; | |
| 2455 | } | |
| 2456 | ||
| 2457 | if (regNum >= UNW_ARM_D16 && regNum <= UNW_ARM_D31) { | |
| 2458 | if (!_saved_vfp_d16_d31) { | |
| 2459 | _saved_vfp_d16_d31 = true; | |
| 2460 | saveVFPv3(_vfp_d16_d31); | |
| 2461 | } | |
| 2462 | return _vfp_d16_d31[regNum - UNW_ARM_D16]; | |
| 2463 | } | |
| 2464 | ||
| 2465 | #if defined(__ARM_WMMX) | |
| 2466 | if (regNum >= UNW_ARM_WR0 && regNum <= UNW_ARM_WR15) { | |
| 2467 | if (!_saved_iwmmx) { | |
| 2468 | _saved_iwmmx = true; | |
| 2469 | saveiWMMX(_iwmmx); | |
| 2470 | } | |
| 2471 | return _iwmmx[regNum - UNW_ARM_WR0]; | |
| 2472 | } | |
| 2473 | #endif | |
| 2474 | ||
| 2475 | _LIBUNWIND_ABORT("Unknown ARM float register"); | |
| 2476 | } | |
| 2477 | ||
| 2478 | inline void Registers_arm::setFloatRegister(int regNum, unw_fpreg_t value) { | |
| 2479 | if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D15) { | |
| 2480 | if (!_saved_vfp_d0_d15) { | |
| 2481 | _saved_vfp_d0_d15 = true; | |
| 2482 | if (_use_X_for_vfp_save) | |
| 2483 | saveVFPWithFSTMX(_vfp_d0_d15_pad); | |
| 2484 | else | |
| 2485 | saveVFPWithFSTMD(_vfp_d0_d15_pad); | |
| 2486 | } | |
| 2487 | _vfp_d0_d15_pad[regNum - UNW_ARM_D0] = value; | |
| 2488 | return; | |
| 2489 | } | |
| 2490 | ||
| 2491 | if (regNum >= UNW_ARM_D16 && regNum <= UNW_ARM_D31) { | |
| 2492 | if (!_saved_vfp_d16_d31) { | |
| 2493 | _saved_vfp_d16_d31 = true; | |
| 2494 | saveVFPv3(_vfp_d16_d31); | |
| 2495 | } | |
| 2496 | _vfp_d16_d31[regNum - UNW_ARM_D16] = value; | |
| 2497 | return; | |
| 2498 | } | |
| 2499 | ||
| 2500 | #if defined(__ARM_WMMX) | |
| 2501 | if (regNum >= UNW_ARM_WR0 && regNum <= UNW_ARM_WR15) { | |
| 2502 | if (!_saved_iwmmx) { | |
| 2503 | _saved_iwmmx = true; | |
| 2504 | saveiWMMX(_iwmmx); | |
| 2505 | } | |
| 2506 | _iwmmx[regNum - UNW_ARM_WR0] = value; | |
| 2507 | return; | |
| 2508 | } | |
| 2509 | #endif | |
| 2510 | ||
| 2511 | _LIBUNWIND_ABORT("Unknown ARM float register"); | |
| 2512 | } | |
| 2513 | ||
| 2514 | inline bool Registers_arm::validVectorRegister(int) const { | |
| 2515 | return false; | |
| 2516 | } | |
| 2517 | ||
| 2518 | inline v128 Registers_arm::getVectorRegister(int) const { | |
| 2519 | _LIBUNWIND_ABORT("ARM vector support not implemented"); | |
| 2520 | } | |
| 2521 | ||
| 2522 | inline void Registers_arm::setVectorRegister(int, v128) { | |
| 2523 | _LIBUNWIND_ABORT("ARM vector support not implemented"); | |
| 2524 | } | |
| 2525 | #endif // _LIBUNWIND_TARGET_ARM | |
| 2526 | ||
| 2527 | ||
| 2528 | #if defined(_LIBUNWIND_TARGET_OR1K) | |
| 2529 | /// Registers_or1k holds the register state of a thread in an OpenRISC1000 | |
| 2530 | /// process. | |
| 2531 | class _LIBUNWIND_HIDDEN Registers_or1k { | |
| 2532 | public: | |
| 2533 | Registers_or1k(); | |
| 2534 | Registers_or1k(const void *registers); | |
| 2535 | ||
| 2536 | bool validRegister(int num) const; | |
| 2537 | uint32_t getRegister(int num) const; | |
| 2538 | void setRegister(int num, uint32_t value); | |
| 2539 | bool validFloatRegister(int num) const; | |
| 2540 | double getFloatRegister(int num) const; | |
| 2541 | void setFloatRegister(int num, double value); | |
| 2542 | bool validVectorRegister(int num) const; | |
| 2543 | v128 getVectorRegister(int num) const; | |
| 2544 | void setVectorRegister(int num, v128 value); | |
| 2545 | static const char *getRegisterName(int num); | |
| 2546 | void jumpto(); | |
| 2547 | static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K; } | |
| 2548 | static int getArch() { return REGISTERS_OR1K; } | |
| 2549 | ||
| 2550 | uint64_t getSP() const { return _registers.__r[1]; } | |
| 2551 | void setSP(uint32_t value) { _registers.__r[1] = value; } | |
| 2552 | uint64_t getIP() const { return _registers.__pc; } | |
| 2553 | void setIP(uint32_t value) { _registers.__pc = value; } | |
| 2554 | ||
| 2555 | private: | |
| 2556 | struct or1k_thread_state_t { | |
| 2557 | unsigned int __r[32]; // r0-r31 | |
| 2558 | unsigned int __pc; // Program counter | |
| 2559 | unsigned int __epcr; // Program counter at exception | |
| 2560 | }; | |
| 2561 | ||
| 2562 | or1k_thread_state_t _registers; | |
| 2563 | }; | |
| 2564 | ||
| 2565 | inline Registers_or1k::Registers_or1k(const void *registers) { | |
| 2566 | static_assert((check_fit<Registers_or1k, unw_context_t>::does_fit), | |
| 2567 | "or1k registers do not fit into unw_context_t"); | |
| 2568 | memcpy(&_registers, static_cast<const uint8_t *>(registers), | |
| 2569 | sizeof(_registers)); | |
| 2570 | } | |
| 2571 | ||
| 2572 | inline Registers_or1k::Registers_or1k() { | |
| 2573 | memset(&_registers, 0, sizeof(_registers)); | |
| 2574 | } | |
| 2575 | ||
| 2576 | inline bool Registers_or1k::validRegister(int regNum) const { | |
| 2577 | if (regNum == UNW_REG_IP) | |
| 2578 | return true; | |
| 2579 | if (regNum == UNW_REG_SP) | |
| 2580 | return true; | |
| 2581 | if (regNum < 0) | |
| 2582 | return false; | |
| 2583 | if (regNum <= UNW_OR1K_R31) | |
| 2584 | return true; | |
| 2585 | if (regNum == UNW_OR1K_EPCR) | |
| 2586 | return true; | |
| 2587 | return false; | |
| 2588 | } | |
| 2589 | ||
| 2590 | inline uint32_t Registers_or1k::getRegister(int regNum) const { | |
| 2591 | if (regNum >= UNW_OR1K_R0 && regNum <= UNW_OR1K_R31) | |
| 2592 | return _registers.__r[regNum - UNW_OR1K_R0]; | |
| 2593 | ||
| 2594 | switch (regNum) { | |
| 2595 | case UNW_REG_IP: | |
| 2596 | return _registers.__pc; | |
| 2597 | case UNW_REG_SP: | |
| 2598 | return _registers.__r[1]; | |
| 2599 | case UNW_OR1K_EPCR: | |
| 2600 | return _registers.__epcr; | |
| 2601 | } | |
| 2602 | _LIBUNWIND_ABORT("unsupported or1k register"); | |
| 2603 | } | |
| 2604 | ||
| 2605 | inline void Registers_or1k::setRegister(int regNum, uint32_t value) { | |
| 2606 | if (regNum >= UNW_OR1K_R0 && regNum <= UNW_OR1K_R31) { | |
| 2607 | _registers.__r[regNum - UNW_OR1K_R0] = value; | |
| 2608 | return; | |
| 2609 | } | |
| 2610 | ||
| 2611 | switch (regNum) { | |
| 2612 | case UNW_REG_IP: | |
| 2613 | _registers.__pc = value; | |
| 2614 | return; | |
| 2615 | case UNW_REG_SP: | |
| 2616 | _registers.__r[1] = value; | |
| 2617 | return; | |
| 2618 | case UNW_OR1K_EPCR: | |
| 2619 | _registers.__epcr = value; | |
| 2620 | return; | |
| 2621 | } | |
| 2622 | _LIBUNWIND_ABORT("unsupported or1k register"); | |
| 2623 | } | |
| 2624 | ||
| 2625 | inline bool Registers_or1k::validFloatRegister(int /* regNum */) const { | |
| 2626 | return false; | |
| 2627 | } | |
| 2628 | ||
| 2629 | inline double Registers_or1k::getFloatRegister(int /* regNum */) const { | |
| 2630 | _LIBUNWIND_ABORT("or1k float support not implemented"); | |
| 2631 | } | |
| 2632 | ||
| 2633 | inline void Registers_or1k::setFloatRegister(int /* regNum */, | |
| 2634 | double /* value */) { | |
| 2635 | _LIBUNWIND_ABORT("or1k float support not implemented"); | |
| 2636 | } | |
| 2637 | ||
| 2638 | inline bool Registers_or1k::validVectorRegister(int /* regNum */) const { | |
| 2639 | return false; | |
| 2640 | } | |
| 2641 | ||
| 2642 | inline v128 Registers_or1k::getVectorRegister(int /* regNum */) const { | |
| 2643 | _LIBUNWIND_ABORT("or1k vector support not implemented"); | |
| 2644 | } | |
| 2645 | ||
| 2646 | inline void Registers_or1k::setVectorRegister(int /* regNum */, v128 /* value */) { | |
| 2647 | _LIBUNWIND_ABORT("or1k vector support not implemented"); | |
| 2648 | } | |
| 2649 | ||
| 2650 | inline const char *Registers_or1k::getRegisterName(int regNum) { | |
| 2651 | switch (regNum) { | |
| 2652 | case UNW_OR1K_R0: | |
| 2653 | return "r0"; | |
| 2654 | case UNW_OR1K_R1: | |
| 2655 | return "r1"; | |
| 2656 | case UNW_OR1K_R2: | |
| 2657 | return "r2"; | |
| 2658 | case UNW_OR1K_R3: | |
| 2659 | return "r3"; | |
| 2660 | case UNW_OR1K_R4: | |
| 2661 | return "r4"; | |
| 2662 | case UNW_OR1K_R5: | |
| 2663 | return "r5"; | |
| 2664 | case UNW_OR1K_R6: | |
| 2665 | return "r6"; | |
| 2666 | case UNW_OR1K_R7: | |
| 2667 | return "r7"; | |
| 2668 | case UNW_OR1K_R8: | |
| 2669 | return "r8"; | |
| 2670 | case UNW_OR1K_R9: | |
| 2671 | return "r9"; | |
| 2672 | case UNW_OR1K_R10: | |
| 2673 | return "r10"; | |
| 2674 | case UNW_OR1K_R11: | |
| 2675 | return "r11"; | |
| 2676 | case UNW_OR1K_R12: | |
| 2677 | return "r12"; | |
| 2678 | case UNW_OR1K_R13: | |
| 2679 | return "r13"; | |
| 2680 | case UNW_OR1K_R14: | |
| 2681 | return "r14"; | |
| 2682 | case UNW_OR1K_R15: | |
| 2683 | return "r15"; | |
| 2684 | case UNW_OR1K_R16: | |
| 2685 | return "r16"; | |
| 2686 | case UNW_OR1K_R17: | |
| 2687 | return "r17"; | |
| 2688 | case UNW_OR1K_R18: | |
| 2689 | return "r18"; | |
| 2690 | case UNW_OR1K_R19: | |
| 2691 | return "r19"; | |
| 2692 | case UNW_OR1K_R20: | |
| 2693 | return "r20"; | |
| 2694 | case UNW_OR1K_R21: | |
| 2695 | return "r21"; | |
| 2696 | case UNW_OR1K_R22: | |
| 2697 | return "r22"; | |
| 2698 | case UNW_OR1K_R23: | |
| 2699 | return "r23"; | |
| 2700 | case UNW_OR1K_R24: | |
| 2701 | return "r24"; | |
| 2702 | case UNW_OR1K_R25: | |
| 2703 | return "r25"; | |
| 2704 | case UNW_OR1K_R26: | |
| 2705 | return "r26"; | |
| 2706 | case UNW_OR1K_R27: | |
| 2707 | return "r27"; | |
| 2708 | case UNW_OR1K_R28: | |
| 2709 | return "r28"; | |
| 2710 | case UNW_OR1K_R29: | |
| 2711 | return "r29"; | |
| 2712 | case UNW_OR1K_R30: | |
| 2713 | return "r30"; | |
| 2714 | case UNW_OR1K_R31: | |
| 2715 | return "r31"; | |
| 2716 | case UNW_OR1K_EPCR: | |
| 2717 | return "EPCR"; | |
| 2718 | default: | |
| 2719 | return "unknown register"; | |
| 2720 | } | |
| 2721 | ||
| 2722 | } | |
| 2723 | #endif // _LIBUNWIND_TARGET_OR1K | |
| 2724 | ||
| 2725 | #if defined(_LIBUNWIND_TARGET_MIPS_O32) | |
| 2726 | /// Registers_mips_o32 holds the register state of a thread in a 32-bit MIPS | |
| 2727 | /// process. | |
| 2728 | class _LIBUNWIND_HIDDEN Registers_mips_o32 { | |
| 2729 | public: | |
| 2730 | Registers_mips_o32(); | |
| 2731 | Registers_mips_o32(const void *registers); | |
| 2732 | ||
| 2733 | bool validRegister(int num) const; | |
| 2734 | uint32_t getRegister(int num) const; | |
| 2735 | void setRegister(int num, uint32_t value); | |
| 2736 | bool validFloatRegister(int num) const; | |
| 2737 | double getFloatRegister(int num) const; | |
| 2738 | void setFloatRegister(int num, double value); | |
| 2739 | bool validVectorRegister(int num) const; | |
| 2740 | v128 getVectorRegister(int num) const; | |
| 2741 | void setVectorRegister(int num, v128 value); | |
| 2742 | static const char *getRegisterName(int num); | |
| 2743 | void jumpto(); | |
| 2744 | static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS; } | |
| 2745 | static int getArch() { return REGISTERS_MIPS_O32; } | |
| 2746 | ||
| 2747 | uint32_t getSP() const { return _registers.__r[29]; } | |
| 2748 | void setSP(uint32_t value) { _registers.__r[29] = value; } | |
| 2749 | uint32_t getIP() const { return _registers.__pc; } | |
| 2750 | void setIP(uint32_t value) { _registers.__pc = value; } | |
| 2751 | ||
| 2752 | private: | |
| 2753 | struct mips_o32_thread_state_t { | |
| 2754 | uint32_t __r[32]; | |
| 2755 | uint32_t __pc; | |
| 2756 | uint32_t __hi; | |
| 2757 | uint32_t __lo; | |
| 2758 | }; | |
| 2759 | ||
| 2760 | mips_o32_thread_state_t _registers; | |
| 2761 | #ifdef __mips_hard_float | |
| 2762 | /// O32 with 32-bit floating point registers only uses half of this | |
| 2763 | /// space. However, using the same layout for 32-bit vs 64-bit | |
| 2764 | /// floating point registers results in a single context size for | |
| 2765 | /// O32 with hard float. | |
| 2766 | uint32_t _padding; | |
| 2767 | double _floats[32]; | |
| 2768 | #endif | |
| 2769 | }; | |
| 2770 | ||
| 2771 | inline Registers_mips_o32::Registers_mips_o32(const void *registers) { | |
| 2772 | static_assert((check_fit<Registers_mips_o32, unw_context_t>::does_fit), | |
| 2773 | "mips_o32 registers do not fit into unw_context_t"); | |
| 2774 | memcpy(&_registers, static_cast<const uint8_t *>(registers), | |
| 2775 | sizeof(_registers)); | |
| 2776 | } | |
| 2777 | ||
| 2778 | inline Registers_mips_o32::Registers_mips_o32() { | |
| 2779 | memset(&_registers, 0, sizeof(_registers)); | |
| 2780 | } | |
| 2781 | ||
| 2782 | inline bool Registers_mips_o32::validRegister(int regNum) const { | |
| 2783 | if (regNum == UNW_REG_IP) | |
| 2784 | return true; | |
| 2785 | if (regNum == UNW_REG_SP) | |
| 2786 | return true; | |
| 2787 | if (regNum < 0) | |
| 2788 | return false; | |
| 2789 | if (regNum <= UNW_MIPS_R31) | |
| 2790 | return true; | |
| 2791 | #if __mips_isa_rev != 6 | |
| 2792 | if (regNum == UNW_MIPS_HI) | |
| 2793 | return true; | |
| 2794 | if (regNum == UNW_MIPS_LO) | |
| 2795 | return true; | |
| 2796 | #endif | |
| 2797 | #if defined(__mips_hard_float) && __mips_fpr == 32 | |
| 2798 | if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) | |
| 2799 | return true; | |
| 2800 | #endif | |
| 2801 | // FIXME: DSP accumulator registers, MSA registers | |
| 2802 | return false; | |
| 2803 | } | |
| 2804 | ||
| 2805 | inline uint32_t Registers_mips_o32::getRegister(int regNum) const { | |
| 2806 | if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31) | |
| 2807 | return _registers.__r[regNum - UNW_MIPS_R0]; | |
| 2808 | #if defined(__mips_hard_float) && __mips_fpr == 32 | |
| 2809 | if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) { | |
| 2810 | uint32_t *p; | |
| 2811 | ||
| 2812 | if (regNum % 2 == 0) | |
| 2813 | p = (uint32_t *)&_floats[regNum - UNW_MIPS_F0]; | |
| 2814 | else | |
| 2815 | p = (uint32_t *)&_floats[(regNum - 1) - UNW_MIPS_F0] + 1; | |
| 2816 | return *p; | |
| 2817 | } | |
| 2818 | #endif | |
| 2819 | ||
| 2820 | switch (regNum) { | |
| 2821 | case UNW_REG_IP: | |
| 2822 | return _registers.__pc; | |
| 2823 | case UNW_REG_SP: | |
| 2824 | return _registers.__r[29]; | |
| 2825 | case UNW_MIPS_HI: | |
| 2826 | return _registers.__hi; | |
| 2827 | case UNW_MIPS_LO: | |
| 2828 | return _registers.__lo; | |
| 2829 | } | |
| 2830 | _LIBUNWIND_ABORT("unsupported mips_o32 register"); | |
| 2831 | } | |
| 2832 | ||
| 2833 | inline void Registers_mips_o32::setRegister(int regNum, uint32_t value) { | |
| 2834 | if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31) { | |
| 2835 | _registers.__r[regNum - UNW_MIPS_R0] = value; | |
| 2836 | return; | |
| 2837 | } | |
| 2838 | #if defined(__mips_hard_float) && __mips_fpr == 32 | |
| 2839 | if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) { | |
| 2840 | uint32_t *p; | |
| 2841 | ||
| 2842 | if (regNum % 2 == 0) | |
| 2843 | p = (uint32_t *)&_floats[regNum - UNW_MIPS_F0]; | |
| 2844 | else | |
| 2845 | p = (uint32_t *)&_floats[(regNum - 1) - UNW_MIPS_F0] + 1; | |
| 2846 | *p = value; | |
| 2847 | return; | |
| 2848 | } | |
| 2849 | #endif | |
| 2850 | ||
| 2851 | switch (regNum) { | |
| 2852 | case UNW_REG_IP: | |
| 2853 | _registers.__pc = value; | |
| 2854 | return; | |
| 2855 | case UNW_REG_SP: | |
| 2856 | _registers.__r[29] = value; | |
| 2857 | return; | |
| 2858 | case UNW_MIPS_HI: | |
| 2859 | _registers.__hi = value; | |
| 2860 | return; | |
| 2861 | case UNW_MIPS_LO: | |
| 2862 | _registers.__lo = value; | |
| 2863 | return; | |
| 2864 | } | |
| 2865 | _LIBUNWIND_ABORT("unsupported mips_o32 register"); | |
| 2866 | } | |
| 2867 | ||
| 2868 | inline bool Registers_mips_o32::validFloatRegister(int regNum) const { | |
| 2869 | #if defined(__mips_hard_float) && __mips_fpr == 64 | |
| 2870 | if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) | |
| 2871 | return true; | |
| 2872 | #endif | |
| 2873 | return false; | |
| 2874 | } | |
| 2875 | ||
| 2876 | inline double Registers_mips_o32::getFloatRegister(int regNum) const { | |
| 2877 | #if defined(__mips_hard_float) && __mips_fpr == 64 | |
| 2878 | assert(validFloatRegister(regNum)); | |
| 2879 | return _floats[regNum - UNW_MIPS_F0]; | |
| 2880 | #else | |
| 2881 | _LIBUNWIND_ABORT("mips_o32 float support not implemented"); | |
| 2882 | #endif | |
| 2883 | } | |
| 2884 | ||
| 2885 | inline void Registers_mips_o32::setFloatRegister(int regNum, | |
| 2886 | double value) { | |
| 2887 | #if defined(__mips_hard_float) && __mips_fpr == 64 | |
| 2888 | assert(validFloatRegister(regNum)); | |
| 2889 | _floats[regNum - UNW_MIPS_F0] = value; | |
| 2890 | #else | |
| 2891 | _LIBUNWIND_ABORT("mips_o32 float support not implemented"); | |
| 2892 | #endif | |
| 2893 | } | |
| 2894 | ||
| 2895 | inline bool Registers_mips_o32::validVectorRegister(int /* regNum */) const { | |
| 2896 | return false; | |
| 2897 | } | |
| 2898 | ||
| 2899 | inline v128 Registers_mips_o32::getVectorRegister(int /* regNum */) const { | |
| 2900 | _LIBUNWIND_ABORT("mips_o32 vector support not implemented"); | |
| 2901 | } | |
| 2902 | ||
| 2903 | inline void Registers_mips_o32::setVectorRegister(int /* regNum */, v128 /* value */) { | |
| 2904 | _LIBUNWIND_ABORT("mips_o32 vector support not implemented"); | |
| 2905 | } | |
| 2906 | ||
| 2907 | inline const char *Registers_mips_o32::getRegisterName(int regNum) { | |
| 2908 | switch (regNum) { | |
| 2909 | case UNW_MIPS_R0: | |
| 2910 | return "$0"; | |
| 2911 | case UNW_MIPS_R1: | |
| 2912 | return "$1"; | |
| 2913 | case UNW_MIPS_R2: | |
| 2914 | return "$2"; | |
| 2915 | case UNW_MIPS_R3: | |
| 2916 | return "$3"; | |
| 2917 | case UNW_MIPS_R4: | |
| 2918 | return "$4"; | |
| 2919 | case UNW_MIPS_R5: | |
| 2920 | return "$5"; | |
| 2921 | case UNW_MIPS_R6: | |
| 2922 | return "$6"; | |
| 2923 | case UNW_MIPS_R7: | |
| 2924 | return "$7"; | |
| 2925 | case UNW_MIPS_R8: | |
| 2926 | return "$8"; | |
| 2927 | case UNW_MIPS_R9: | |
| 2928 | return "$9"; | |
| 2929 | case UNW_MIPS_R10: | |
| 2930 | return "$10"; | |
| 2931 | case UNW_MIPS_R11: | |
| 2932 | return "$11"; | |
| 2933 | case UNW_MIPS_R12: | |
| 2934 | return "$12"; | |
| 2935 | case UNW_MIPS_R13: | |
| 2936 | return "$13"; | |
| 2937 | case UNW_MIPS_R14: | |
| 2938 | return "$14"; | |
| 2939 | case UNW_MIPS_R15: | |
| 2940 | return "$15"; | |
| 2941 | case UNW_MIPS_R16: | |
| 2942 | return "$16"; | |
| 2943 | case UNW_MIPS_R17: | |
| 2944 | return "$17"; | |
| 2945 | case UNW_MIPS_R18: | |
| 2946 | return "$18"; | |
| 2947 | case UNW_MIPS_R19: | |
| 2948 | return "$19"; | |
| 2949 | case UNW_MIPS_R20: | |
| 2950 | return "$20"; | |
| 2951 | case UNW_MIPS_R21: | |
| 2952 | return "$21"; | |
| 2953 | case UNW_MIPS_R22: | |
| 2954 | return "$22"; | |
| 2955 | case UNW_MIPS_R23: | |
| 2956 | return "$23"; | |
| 2957 | case UNW_MIPS_R24: | |
| 2958 | return "$24"; | |
| 2959 | case UNW_MIPS_R25: | |
| 2960 | return "$25"; | |
| 2961 | case UNW_MIPS_R26: | |
| 2962 | return "$26"; | |
| 2963 | case UNW_MIPS_R27: | |
| 2964 | return "$27"; | |
| 2965 | case UNW_MIPS_R28: | |
| 2966 | return "$28"; | |
| 2967 | case UNW_MIPS_R29: | |
| 2968 | return "$29"; | |
| 2969 | case UNW_MIPS_R30: | |
| 2970 | return "$30"; | |
| 2971 | case UNW_MIPS_R31: | |
| 2972 | return "$31"; | |
| 2973 | case UNW_MIPS_F0: | |
| 2974 | return "$f0"; | |
| 2975 | case UNW_MIPS_F1: | |
| 2976 | return "$f1"; | |
| 2977 | case UNW_MIPS_F2: | |
| 2978 | return "$f2"; | |
| 2979 | case UNW_MIPS_F3: | |
| 2980 | return "$f3"; | |
| 2981 | case UNW_MIPS_F4: | |
| 2982 | return "$f4"; | |
| 2983 | case UNW_MIPS_F5: | |
| 2984 | return "$f5"; | |
| 2985 | case UNW_MIPS_F6: | |
| 2986 | return "$f6"; | |
| 2987 | case UNW_MIPS_F7: | |
| 2988 | return "$f7"; | |
| 2989 | case UNW_MIPS_F8: | |
| 2990 | return "$f8"; | |
| 2991 | case UNW_MIPS_F9: | |
| 2992 | return "$f9"; | |
| 2993 | case UNW_MIPS_F10: | |
| 2994 | return "$f10"; | |
| 2995 | case UNW_MIPS_F11: | |
| 2996 | return "$f11"; | |
| 2997 | case UNW_MIPS_F12: | |
| 2998 | return "$f12"; | |
| 2999 | case UNW_MIPS_F13: | |
| 3000 | return "$f13"; | |
| 3001 | case UNW_MIPS_F14: | |
| 3002 | return "$f14"; | |
| 3003 | case UNW_MIPS_F15: | |
| 3004 | return "$f15"; | |
| 3005 | case UNW_MIPS_F16: | |
| 3006 | return "$f16"; | |
| 3007 | case UNW_MIPS_F17: | |
| 3008 | return "$f17"; | |
| 3009 | case UNW_MIPS_F18: | |
| 3010 | return "$f18"; | |
| 3011 | case UNW_MIPS_F19: | |
| 3012 | return "$f19"; | |
| 3013 | case UNW_MIPS_F20: | |
| 3014 | return "$f20"; | |
| 3015 | case UNW_MIPS_F21: | |
| 3016 | return "$f21"; | |
| 3017 | case UNW_MIPS_F22: | |
| 3018 | return "$f22"; | |
| 3019 | case UNW_MIPS_F23: | |
| 3020 | return "$f23"; | |
| 3021 | case UNW_MIPS_F24: | |
| 3022 | return "$f24"; | |
| 3023 | case UNW_MIPS_F25: | |
| 3024 | return "$f25"; | |
| 3025 | case UNW_MIPS_F26: | |
| 3026 | return "$f26"; | |
| 3027 | case UNW_MIPS_F27: | |
| 3028 | return "$f27"; | |
| 3029 | case UNW_MIPS_F28: | |
| 3030 | return "$f28"; | |
| 3031 | case UNW_MIPS_F29: | |
| 3032 | return "$f29"; | |
| 3033 | case UNW_MIPS_F30: | |
| 3034 | return "$f30"; | |
| 3035 | case UNW_MIPS_F31: | |
| 3036 | return "$f31"; | |
| 3037 | case UNW_MIPS_HI: | |
| 3038 | return "$hi"; | |
| 3039 | case UNW_MIPS_LO: | |
| 3040 | return "$lo"; | |
| 3041 | default: | |
| 3042 | return "unknown register"; | |
| 3043 | } | |
| 3044 | } | |
| 3045 | #endif // _LIBUNWIND_TARGET_MIPS_O32 | |
| 3046 | ||
| 3047 | #if defined(_LIBUNWIND_TARGET_MIPS_NEWABI) | |
| 3048 | /// Registers_mips_newabi holds the register state of a thread in a | |
| 3049 | /// MIPS process using NEWABI (the N32 or N64 ABIs). | |
| 3050 | class _LIBUNWIND_HIDDEN Registers_mips_newabi { | |
| 3051 | public: | |
| 3052 | Registers_mips_newabi(); | |
| 3053 | Registers_mips_newabi(const void *registers); | |
| 3054 | ||
| 3055 | bool validRegister(int num) const; | |
| 3056 | uint64_t getRegister(int num) const; | |
| 3057 | void setRegister(int num, uint64_t value); | |
| 3058 | bool validFloatRegister(int num) const; | |
| 3059 | double getFloatRegister(int num) const; | |
| 3060 | void setFloatRegister(int num, double value); | |
| 3061 | bool validVectorRegister(int num) const; | |
| 3062 | v128 getVectorRegister(int num) const; | |
| 3063 | void setVectorRegister(int num, v128 value); | |
| 3064 | static const char *getRegisterName(int num); | |
| 3065 | void jumpto(); | |
| 3066 | static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS; } | |
| 3067 | static int getArch() { return REGISTERS_MIPS_NEWABI; } | |
| 3068 | ||
| 3069 | uint64_t getSP() const { return _registers.__r[29]; } | |
| 3070 | void setSP(uint64_t value) { _registers.__r[29] = value; } | |
| 3071 | uint64_t getIP() const { return _registers.__pc; } | |
| 3072 | void setIP(uint64_t value) { _registers.__pc = value; } | |
| 3073 | ||
| 3074 | private: | |
| 3075 | struct mips_newabi_thread_state_t { | |
| 3076 | uint64_t __r[32]; | |
| 3077 | uint64_t __pc; | |
| 3078 | uint64_t __hi; | |
| 3079 | uint64_t __lo; | |
| 3080 | }; | |
| 3081 | ||
| 3082 | mips_newabi_thread_state_t _registers; | |
| 3083 | #ifdef __mips_hard_float | |
| 3084 | double _floats[32]; | |
| 3085 | #endif | |
| 3086 | }; | |
| 3087 | ||
| 3088 | inline Registers_mips_newabi::Registers_mips_newabi(const void *registers) { | |
| 3089 | static_assert((check_fit<Registers_mips_newabi, unw_context_t>::does_fit), | |
| 3090 | "mips_newabi registers do not fit into unw_context_t"); | |
| 3091 | memcpy(&_registers, static_cast<const uint8_t *>(registers), | |
| 3092 | sizeof(_registers)); | |
| 3093 | } | |
| 3094 | ||
| 3095 | inline Registers_mips_newabi::Registers_mips_newabi() { | |
| 3096 | memset(&_registers, 0, sizeof(_registers)); | |
| 3097 | } | |
| 3098 | ||
| 3099 | inline bool Registers_mips_newabi::validRegister(int regNum) const { | |
| 3100 | if (regNum == UNW_REG_IP) | |
| 3101 | return true; | |
| 3102 | if (regNum == UNW_REG_SP) | |
| 3103 | return true; | |
| 3104 | if (regNum < 0) | |
| 3105 | return false; | |
| 3106 | if (regNum <= UNW_MIPS_R31) | |
| 3107 | return true; | |
| 3108 | #if __mips_isa_rev != 6 | |
| 3109 | if (regNum == UNW_MIPS_HI) | |
| 3110 | return true; | |
| 3111 | if (regNum == UNW_MIPS_LO) | |
| 3112 | return true; | |
| 3113 | #endif | |
| 3114 | // FIXME: Hard float, DSP accumulator registers, MSA registers | |
| 3115 | return false; | |
| 3116 | } | |
| 3117 | ||
| 3118 | inline uint64_t Registers_mips_newabi::getRegister(int regNum) const { | |
| 3119 | if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31) | |
| 3120 | return _registers.__r[regNum - UNW_MIPS_R0]; | |
| 3121 | ||
| 3122 | switch (regNum) { | |
| 3123 | case UNW_REG_IP: | |
| 3124 | return _registers.__pc; | |
| 3125 | case UNW_REG_SP: | |
| 3126 | return _registers.__r[29]; | |
| 3127 | case UNW_MIPS_HI: | |
| 3128 | return _registers.__hi; | |
| 3129 | case UNW_MIPS_LO: | |
| 3130 | return _registers.__lo; | |
| 3131 | } | |
| 3132 | _LIBUNWIND_ABORT("unsupported mips_newabi register"); | |
| 3133 | } | |
| 3134 | ||
| 3135 | inline void Registers_mips_newabi::setRegister(int regNum, uint64_t value) { | |
| 3136 | if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31) { | |
| 3137 | _registers.__r[regNum - UNW_MIPS_R0] = value; | |
| 3138 | return; | |
| 3139 | } | |
| 3140 | ||
| 3141 | switch (regNum) { | |
| 3142 | case UNW_REG_IP: | |
| 3143 | _registers.__pc = value; | |
| 3144 | return; | |
| 3145 | case UNW_REG_SP: | |
| 3146 | _registers.__r[29] = value; | |
| 3147 | return; | |
| 3148 | case UNW_MIPS_HI: | |
| 3149 | _registers.__hi = value; | |
| 3150 | return; | |
| 3151 | case UNW_MIPS_LO: | |
| 3152 | _registers.__lo = value; | |
| 3153 | return; | |
| 3154 | } | |
| 3155 | _LIBUNWIND_ABORT("unsupported mips_newabi register"); | |
| 3156 | } | |
| 3157 | ||
| 3158 | inline bool Registers_mips_newabi::validFloatRegister(int regNum) const { | |
| 3159 | #ifdef __mips_hard_float | |
| 3160 | if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) | |
| 3161 | return true; | |
| 3162 | #endif | |
| 3163 | return false; | |
| 3164 | } | |
| 3165 | ||
| 3166 | inline double Registers_mips_newabi::getFloatRegister(int regNum) const { | |
| 3167 | #ifdef __mips_hard_float | |
| 3168 | assert(validFloatRegister(regNum)); | |
| 3169 | return _floats[regNum - UNW_MIPS_F0]; | |
| 3170 | #else | |
| 3171 | _LIBUNWIND_ABORT("mips_newabi float support not implemented"); | |
| 3172 | #endif | |
| 3173 | } | |
| 3174 | ||
| 3175 | inline void Registers_mips_newabi::setFloatRegister(int regNum, | |
| 3176 | double value) { | |
| 3177 | #ifdef __mips_hard_float | |
| 3178 | assert(validFloatRegister(regNum)); | |
| 3179 | _floats[regNum - UNW_MIPS_F0] = value; | |
| 3180 | #else | |
| 3181 | _LIBUNWIND_ABORT("mips_newabi float support not implemented"); | |
| 3182 | #endif | |
| 3183 | } | |
| 3184 | ||
| 3185 | inline bool Registers_mips_newabi::validVectorRegister(int /* regNum */) const { | |
| 3186 | return false; | |
| 3187 | } | |
| 3188 | ||
| 3189 | inline v128 Registers_mips_newabi::getVectorRegister(int /* regNum */) const { | |
| 3190 | _LIBUNWIND_ABORT("mips_newabi vector support not implemented"); | |
| 3191 | } | |
| 3192 | ||
| 3193 | inline void Registers_mips_newabi::setVectorRegister(int /* regNum */, v128 /* value */) { | |
| 3194 | _LIBUNWIND_ABORT("mips_newabi vector support not implemented"); | |
| 3195 | } | |
| 3196 | ||
| 3197 | inline const char *Registers_mips_newabi::getRegisterName(int regNum) { | |
| 3198 | switch (regNum) { | |
| 3199 | case UNW_MIPS_R0: | |
| 3200 | return "$0"; | |
| 3201 | case UNW_MIPS_R1: | |
| 3202 | return "$1"; | |
| 3203 | case UNW_MIPS_R2: | |
| 3204 | return "$2"; | |
| 3205 | case UNW_MIPS_R3: | |
| 3206 | return "$3"; | |
| 3207 | case UNW_MIPS_R4: | |
| 3208 | return "$4"; | |
| 3209 | case UNW_MIPS_R5: | |
| 3210 | return "$5"; | |
| 3211 | case UNW_MIPS_R6: | |
| 3212 | return "$6"; | |
| 3213 | case UNW_MIPS_R7: | |
| 3214 | return "$7"; | |
| 3215 | case UNW_MIPS_R8: | |
| 3216 | return "$8"; | |
| 3217 | case UNW_MIPS_R9: | |
| 3218 | return "$9"; | |
| 3219 | case UNW_MIPS_R10: | |
| 3220 | return "$10"; | |
| 3221 | case UNW_MIPS_R11: | |
| 3222 | return "$11"; | |
| 3223 | case UNW_MIPS_R12: | |
| 3224 | return "$12"; | |
| 3225 | case UNW_MIPS_R13: | |
| 3226 | return "$13"; | |
| 3227 | case UNW_MIPS_R14: | |
| 3228 | return "$14"; | |
| 3229 | case UNW_MIPS_R15: | |
| 3230 | return "$15"; | |
| 3231 | case UNW_MIPS_R16: | |
| 3232 | return "$16"; | |
| 3233 | case UNW_MIPS_R17: | |
| 3234 | return "$17"; | |
| 3235 | case UNW_MIPS_R18: | |
| 3236 | return "$18"; | |
| 3237 | case UNW_MIPS_R19: | |
| 3238 | return "$19"; | |
| 3239 | case UNW_MIPS_R20: | |
| 3240 | return "$20"; | |
| 3241 | case UNW_MIPS_R21: | |
| 3242 | return "$21"; | |
| 3243 | case UNW_MIPS_R22: | |
| 3244 | return "$22"; | |
| 3245 | case UNW_MIPS_R23: | |
| 3246 | return "$23"; | |
| 3247 | case UNW_MIPS_R24: | |
| 3248 | return "$24"; | |
| 3249 | case UNW_MIPS_R25: | |
| 3250 | return "$25"; | |
| 3251 | case UNW_MIPS_R26: | |
| 3252 | return "$26"; | |
| 3253 | case UNW_MIPS_R27: | |
| 3254 | return "$27"; | |
| 3255 | case UNW_MIPS_R28: | |
| 3256 | return "$28"; | |
| 3257 | case UNW_MIPS_R29: | |
| 3258 | return "$29"; | |
| 3259 | case UNW_MIPS_R30: | |
| 3260 | return "$30"; | |
| 3261 | case UNW_MIPS_R31: | |
| 3262 | return "$31"; | |
| 3263 | case UNW_MIPS_F0: | |
| 3264 | return "$f0"; | |
| 3265 | case UNW_MIPS_F1: | |
| 3266 | return "$f1"; | |
| 3267 | case UNW_MIPS_F2: | |
| 3268 | return "$f2"; | |
| 3269 | case UNW_MIPS_F3: | |
| 3270 | return "$f3"; | |
| 3271 | case UNW_MIPS_F4: | |
| 3272 | return "$f4"; | |
| 3273 | case UNW_MIPS_F5: | |
| 3274 | return "$f5"; | |
| 3275 | case UNW_MIPS_F6: | |
| 3276 | return "$f6"; | |
| 3277 | case UNW_MIPS_F7: | |
| 3278 | return "$f7"; | |
| 3279 | case UNW_MIPS_F8: | |
| 3280 | return "$f8"; | |
| 3281 | case UNW_MIPS_F9: | |
| 3282 | return "$f9"; | |
| 3283 | case UNW_MIPS_F10: | |
| 3284 | return "$f10"; | |
| 3285 | case UNW_MIPS_F11: | |
| 3286 | return "$f11"; | |
| 3287 | case UNW_MIPS_F12: | |
| 3288 | return "$f12"; | |
| 3289 | case UNW_MIPS_F13: | |
| 3290 | return "$f13"; | |
| 3291 | case UNW_MIPS_F14: | |
| 3292 | return "$f14"; | |
| 3293 | case UNW_MIPS_F15: | |
| 3294 | return "$f15"; | |
| 3295 | case UNW_MIPS_F16: | |
| 3296 | return "$f16"; | |
| 3297 | case UNW_MIPS_F17: | |
| 3298 | return "$f17"; | |
| 3299 | case UNW_MIPS_F18: | |
| 3300 | return "$f18"; | |
| 3301 | case UNW_MIPS_F19: | |
| 3302 | return "$f19"; | |
| 3303 | case UNW_MIPS_F20: | |
| 3304 | return "$f20"; | |
| 3305 | case UNW_MIPS_F21: | |
| 3306 | return "$f21"; | |
| 3307 | case UNW_MIPS_F22: | |
| 3308 | return "$f22"; | |
| 3309 | case UNW_MIPS_F23: | |
| 3310 | return "$f23"; | |
| 3311 | case UNW_MIPS_F24: | |
| 3312 | return "$f24"; | |
| 3313 | case UNW_MIPS_F25: | |
| 3314 | return "$f25"; | |
| 3315 | case UNW_MIPS_F26: | |
| 3316 | return "$f26"; | |
| 3317 | case UNW_MIPS_F27: | |
| 3318 | return "$f27"; | |
| 3319 | case UNW_MIPS_F28: | |
| 3320 | return "$f28"; | |
| 3321 | case UNW_MIPS_F29: | |
| 3322 | return "$f29"; | |
| 3323 | case UNW_MIPS_F30: | |
| 3324 | return "$f30"; | |
| 3325 | case UNW_MIPS_F31: | |
| 3326 | return "$f31"; | |
| 3327 | case UNW_MIPS_HI: | |
| 3328 | return "$hi"; | |
| 3329 | case UNW_MIPS_LO: | |
| 3330 | return "$lo"; | |
| 3331 | default: | |
| 3332 | return "unknown register"; | |
| 3333 | } | |
| 3334 | } | |
| 3335 | #endif // _LIBUNWIND_TARGET_MIPS_NEWABI | |
| 3336 | ||
| 3337 | #if defined(_LIBUNWIND_TARGET_SPARC) | |
| 3338 | /// Registers_sparc holds the register state of a thread in a 32-bit Sparc | |
| 3339 | /// process. | |
| 3340 | class _LIBUNWIND_HIDDEN Registers_sparc { | |
| 3341 | public: | |
| 3342 | Registers_sparc(); | |
| 3343 | Registers_sparc(const void *registers); | |
| 3344 | ||
| 3345 | bool validRegister(int num) const; | |
| 3346 | uint32_t getRegister(int num) const; | |
| 3347 | void setRegister(int num, uint32_t value); | |
| 3348 | bool validFloatRegister(int num) const; | |
| 3349 | double getFloatRegister(int num) const; | |
| 3350 | void setFloatRegister(int num, double value); | |
| 3351 | bool validVectorRegister(int num) const; | |
| 3352 | v128 getVectorRegister(int num) const; | |
| 3353 | void setVectorRegister(int num, v128 value); | |
| 3354 | static const char *getRegisterName(int num); | |
| 3355 | void jumpto(); | |
| 3356 | static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC; } | |
| 3357 | static int getArch() { return REGISTERS_SPARC; } | |
| 3358 | ||
| 3359 | uint64_t getSP() const { return _registers.__regs[UNW_SPARC_O6]; } | |
| 3360 | void setSP(uint32_t value) { _registers.__regs[UNW_SPARC_O6] = value; } | |
| 3361 | uint64_t getIP() const { return _registers.__regs[UNW_SPARC_O7]; } | |
| 3362 | void setIP(uint32_t value) { _registers.__regs[UNW_SPARC_O7] = value; } | |
| 3363 | ||
| 3364 | private: | |
| 3365 | struct sparc_thread_state_t { | |
| 3366 | unsigned int __regs[32]; | |
| 3367 | }; | |
| 3368 | ||
| 3369 | sparc_thread_state_t _registers; | |
| 3370 | }; | |
| 3371 | ||
| 3372 | inline Registers_sparc::Registers_sparc(const void *registers) { | |
| 3373 | static_assert((check_fit<Registers_sparc, unw_context_t>::does_fit), | |
| 3374 | "sparc registers do not fit into unw_context_t"); | |
| 3375 | memcpy(&_registers, static_cast<const uint8_t *>(registers), | |
| 3376 | sizeof(_registers)); | |
| 3377 | } | |
| 3378 | ||
| 3379 | inline Registers_sparc::Registers_sparc() { | |
| 3380 | memset(&_registers, 0, sizeof(_registers)); | |
| 3381 | } | |
| 3382 | ||
| 3383 | inline bool Registers_sparc::validRegister(int regNum) const { | |
| 3384 | if (regNum == UNW_REG_IP) | |
| 3385 | return true; | |
| 3386 | if (regNum == UNW_REG_SP) | |
| 3387 | return true; | |
| 3388 | if (regNum < 0) | |
| 3389 | return false; | |
| 3390 | if (regNum <= UNW_SPARC_I7) | |
| 3391 | return true; | |
| 3392 | return false; | |
| 3393 | } | |
| 3394 | ||
| 3395 | inline uint32_t Registers_sparc::getRegister(int regNum) const { | |
| 3396 | if ((UNW_SPARC_G0 <= regNum) && (regNum <= UNW_SPARC_I7)) { | |
| 3397 | return _registers.__regs[regNum]; | |
| 3398 | } | |
| 3399 | ||
| 3400 | switch (regNum) { | |
| 3401 | case UNW_REG_IP: | |
| 3402 | return _registers.__regs[UNW_SPARC_O7]; | |
| 3403 | case UNW_REG_SP: | |
| 3404 | return _registers.__regs[UNW_SPARC_O6]; | |
| 3405 | } | |
| 3406 | _LIBUNWIND_ABORT("unsupported sparc register"); | |
| 3407 | } | |
| 3408 | ||
| 3409 | inline void Registers_sparc::setRegister(int regNum, uint32_t value) { | |
| 3410 | if ((UNW_SPARC_G0 <= regNum) && (regNum <= UNW_SPARC_I7)) { | |
| 3411 | _registers.__regs[regNum] = value; | |
| 3412 | return; | |
| 3413 | } | |
| 3414 | ||
| 3415 | switch (regNum) { | |
| 3416 | case UNW_REG_IP: | |
| 3417 | _registers.__regs[UNW_SPARC_O7] = value; | |
| 3418 | return; | |
| 3419 | case UNW_REG_SP: | |
| 3420 | _registers.__regs[UNW_SPARC_O6] = value; | |
| 3421 | return; | |
| 3422 | } | |
| 3423 | _LIBUNWIND_ABORT("unsupported sparc register"); | |
| 3424 | } | |
| 3425 | ||
| 3426 | inline bool Registers_sparc::validFloatRegister(int) const { return false; } | |
| 3427 | ||
| 3428 | inline double Registers_sparc::getFloatRegister(int) const { | |
| 3429 | _LIBUNWIND_ABORT("no Sparc float registers"); | |
| 3430 | } | |
| 3431 | ||
| 3432 | inline void Registers_sparc::setFloatRegister(int, double) { | |
| 3433 | _LIBUNWIND_ABORT("no Sparc float registers"); | |
| 3434 | } | |
| 3435 | ||
| 3436 | inline bool Registers_sparc::validVectorRegister(int) const { return false; } | |
| 3437 | ||
| 3438 | inline v128 Registers_sparc::getVectorRegister(int) const { | |
| 3439 | _LIBUNWIND_ABORT("no Sparc vector registers"); | |
| 3440 | } | |
| 3441 | ||
| 3442 | inline void Registers_sparc::setVectorRegister(int, v128) { | |
| 3443 | _LIBUNWIND_ABORT("no Sparc vector registers"); | |
| 3444 | } | |
| 3445 | ||
| 3446 | inline const char *Registers_sparc::getRegisterName(int regNum) { | |
| 3447 | switch (regNum) { | |
| 3448 | case UNW_REG_IP: | |
| 3449 | return "pc"; | |
| 3450 | case UNW_SPARC_G0: | |
| 3451 | return "g0"; | |
| 3452 | case UNW_SPARC_G1: | |
| 3453 | return "g1"; | |
| 3454 | case UNW_SPARC_G2: | |
| 3455 | return "g2"; | |
| 3456 | case UNW_SPARC_G3: | |
| 3457 | return "g3"; | |
| 3458 | case UNW_SPARC_G4: | |
| 3459 | return "g4"; | |
| 3460 | case UNW_SPARC_G5: | |
| 3461 | return "g5"; | |
| 3462 | case UNW_SPARC_G6: | |
| 3463 | return "g6"; | |
| 3464 | case UNW_SPARC_G7: | |
| 3465 | return "g7"; | |
| 3466 | case UNW_SPARC_O0: | |
| 3467 | return "o0"; | |
| 3468 | case UNW_SPARC_O1: | |
| 3469 | return "o1"; | |
| 3470 | case UNW_SPARC_O2: | |
| 3471 | return "o2"; | |
| 3472 | case UNW_SPARC_O3: | |
| 3473 | return "o3"; | |
| 3474 | case UNW_SPARC_O4: | |
| 3475 | return "o4"; | |
| 3476 | case UNW_SPARC_O5: | |
| 3477 | return "o5"; | |
| 3478 | case UNW_REG_SP: | |
| 3479 | case UNW_SPARC_O6: | |
| 3480 | return "sp"; | |
| 3481 | case UNW_SPARC_O7: | |
| 3482 | return "o7"; | |
| 3483 | case UNW_SPARC_L0: | |
| 3484 | return "l0"; | |
| 3485 | case UNW_SPARC_L1: | |
| 3486 | return "l1"; | |
| 3487 | case UNW_SPARC_L2: | |
| 3488 | return "l2"; | |
| 3489 | case UNW_SPARC_L3: | |
| 3490 | return "l3"; | |
| 3491 | case UNW_SPARC_L4: | |
| 3492 | return "l4"; | |
| 3493 | case UNW_SPARC_L5: | |
| 3494 | return "l5"; | |
| 3495 | case UNW_SPARC_L6: | |
| 3496 | return "l6"; | |
| 3497 | case UNW_SPARC_L7: | |
| 3498 | return "l7"; | |
| 3499 | case UNW_SPARC_I0: | |
| 3500 | return "i0"; | |
| 3501 | case UNW_SPARC_I1: | |
| 3502 | return "i1"; | |
| 3503 | case UNW_SPARC_I2: | |
| 3504 | return "i2"; | |
| 3505 | case UNW_SPARC_I3: | |
| 3506 | return "i3"; | |
| 3507 | case UNW_SPARC_I4: | |
| 3508 | return "i4"; | |
| 3509 | case UNW_SPARC_I5: | |
| 3510 | return "i5"; | |
| 3511 | case UNW_SPARC_I6: | |
| 3512 | return "fp"; | |
| 3513 | case UNW_SPARC_I7: | |
| 3514 | return "i7"; | |
| 3515 | default: | |
| 3516 | return "unknown register"; | |
| 3517 | } | |
| 3518 | } | |
| 3519 | #endif // _LIBUNWIND_TARGET_SPARC | |
| 3520 | ||
| 3521 | } // namespace libunwind | |
| 3522 | ||
| 3523 | #endif // __REGISTERS_HPP__ |
libunwind/src/Unwind-EHABI.cpp created+991| ... | ... | @@ -0,0 +1,991 @@ |
| 1 | //===--------------------------- Unwind-EHABI.cpp -------------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is dual licensed under the MIT and the University of Illinois Open | |
| 6 | // Source Licenses. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | // | |
| 9 | // Implements ARM zero-cost C++ exceptions | |
| 10 | // | |
| 11 | //===----------------------------------------------------------------------===// | |
| 12 | ||
| 13 | #include "Unwind-EHABI.h" | |
| 14 | ||
| 15 | #if defined(_LIBUNWIND_ARM_EHABI) | |
| 16 | ||
| 17 | #include <inttypes.h> | |
| 18 | #include <stdbool.h> | |
| 19 | #include <stdint.h> | |
| 20 | #include <stdio.h> | |
| 21 | #include <stdlib.h> | |
| 22 | #include <string.h> | |
| 23 | ||
| 24 | #include <type_traits> | |
| 25 | ||
| 26 | #include "config.h" | |
| 27 | #include "libunwind.h" | |
| 28 | #include "libunwind_ext.h" | |
| 29 | #include "unwind.h" | |
| 30 | ||
| 31 | namespace { | |
| 32 | ||
| 33 | // Strange order: take words in order, but inside word, take from most to least | |
| 34 | // signinficant byte. | |
| 35 | uint8_t getByte(const uint32_t* data, size_t offset) { | |
| 36 | const uint8_t* byteData = reinterpret_cast<const uint8_t*>(data); | |
| 37 | return byteData[(offset & ~(size_t)0x03) + (3 - (offset & (size_t)0x03))]; | |
| 38 | } | |
| 39 | ||
| 40 | const char* getNextWord(const char* data, uint32_t* out) { | |
| 41 | *out = *reinterpret_cast<const uint32_t*>(data); | |
| 42 | return data + 4; | |
| 43 | } | |
| 44 | ||
| 45 | const char* getNextNibble(const char* data, uint32_t* out) { | |
| 46 | *out = *reinterpret_cast<const uint16_t*>(data); | |
| 47 | return data + 2; | |
| 48 | } | |
| 49 | ||
| 50 | struct Descriptor { | |
| 51 | // See # 9.2 | |
| 52 | typedef enum { | |
| 53 | SU16 = 0, // Short descriptor, 16-bit entries | |
| 54 | LU16 = 1, // Long descriptor, 16-bit entries | |
| 55 | LU32 = 3, // Long descriptor, 32-bit entries | |
| 56 | RESERVED0 = 4, RESERVED1 = 5, RESERVED2 = 6, RESERVED3 = 7, | |
| 57 | RESERVED4 = 8, RESERVED5 = 9, RESERVED6 = 10, RESERVED7 = 11, | |
| 58 | RESERVED8 = 12, RESERVED9 = 13, RESERVED10 = 14, RESERVED11 = 15 | |
| 59 | } Format; | |
| 60 | ||
| 61 | // See # 9.2 | |
| 62 | typedef enum { | |
| 63 | CLEANUP = 0x0, | |
| 64 | FUNC = 0x1, | |
| 65 | CATCH = 0x2, | |
| 66 | INVALID = 0x4 | |
| 67 | } Kind; | |
| 68 | }; | |
| 69 | ||
| 70 | _Unwind_Reason_Code ProcessDescriptors( | |
| 71 | _Unwind_State state, | |
| 72 | _Unwind_Control_Block* ucbp, | |
| 73 | struct _Unwind_Context* context, | |
| 74 | Descriptor::Format format, | |
| 75 | const char* descriptorStart, | |
| 76 | uint32_t flags) { | |
| 77 | ||
| 78 | // EHT is inlined in the index using compact form. No descriptors. #5 | |
| 79 | if (flags & 0x1) | |
| 80 | return _URC_CONTINUE_UNWIND; | |
| 81 | ||
| 82 | // TODO: We should check the state here, and determine whether we need to | |
| 83 | // perform phase1 or phase2 unwinding. | |
| 84 | (void)state; | |
| 85 | ||
| 86 | const char* descriptor = descriptorStart; | |
| 87 | uint32_t descriptorWord; | |
| 88 | getNextWord(descriptor, &descriptorWord); | |
| 89 | while (descriptorWord) { | |
| 90 | // Read descriptor based on # 9.2. | |
| 91 | uint32_t length; | |
| 92 | uint32_t offset; | |
| 93 | switch (format) { | |
| 94 | case Descriptor::LU32: | |
| 95 | descriptor = getNextWord(descriptor, &length); | |
| 96 | descriptor = getNextWord(descriptor, &offset); | |
| 97 | case Descriptor::LU16: | |
| 98 | descriptor = getNextNibble(descriptor, &length); | |
| 99 | descriptor = getNextNibble(descriptor, &offset); | |
| 100 | default: | |
| 101 | assert(false); | |
| 102 | return _URC_FAILURE; | |
| 103 | } | |
| 104 | ||
| 105 | // See # 9.2 table for decoding the kind of descriptor. It's a 2-bit value. | |
| 106 | Descriptor::Kind kind = | |
| 107 | static_cast<Descriptor::Kind>((length & 0x1) | ((offset & 0x1) << 1)); | |
| 108 | ||
| 109 | // Clear off flag from last bit. | |
| 110 | length &= ~1u; | |
| 111 | offset &= ~1u; | |
| 112 | uintptr_t scopeStart = ucbp->pr_cache.fnstart + offset; | |
| 113 | uintptr_t scopeEnd = scopeStart + length; | |
| 114 | uintptr_t pc = _Unwind_GetIP(context); | |
| 115 | bool isInScope = (scopeStart <= pc) && (pc < scopeEnd); | |
| 116 | ||
| 117 | switch (kind) { | |
| 118 | case Descriptor::CLEANUP: { | |
| 119 | // TODO(ajwong): Handle cleanup descriptors. | |
| 120 | break; | |
| 121 | } | |
| 122 | case Descriptor::FUNC: { | |
| 123 | // TODO(ajwong): Handle function descriptors. | |
| 124 | break; | |
| 125 | } | |
| 126 | case Descriptor::CATCH: { | |
| 127 | // Catch descriptors require gobbling one more word. | |
| 128 | uint32_t landing_pad; | |
| 129 | descriptor = getNextWord(descriptor, &landing_pad); | |
| 130 | ||
| 131 | if (isInScope) { | |
| 132 | // TODO(ajwong): This is only phase1 compatible logic. Implement | |
| 133 | // phase2. | |
| 134 | landing_pad = signExtendPrel31(landing_pad & ~0x80000000); | |
| 135 | if (landing_pad == 0xffffffff) { | |
| 136 | return _URC_HANDLER_FOUND; | |
| 137 | } else if (landing_pad == 0xfffffffe) { | |
| 138 | return _URC_FAILURE; | |
| 139 | } else { | |
| 140 | /* | |
| 141 | bool is_reference_type = landing_pad & 0x80000000; | |
| 142 | void* matched_object; | |
| 143 | if (__cxxabiv1::__cxa_type_match( | |
| 144 | ucbp, reinterpret_cast<const std::type_info *>(landing_pad), | |
| 145 | is_reference_type, | |
| 146 | &matched_object) != __cxxabiv1::ctm_failed) | |
| 147 | return _URC_HANDLER_FOUND; | |
| 148 | */ | |
| 149 | _LIBUNWIND_ABORT("Type matching not implemented"); | |
| 150 | } | |
| 151 | } | |
| 152 | break; | |
| 153 | } | |
| 154 | default: | |
| 155 | _LIBUNWIND_ABORT("Invalid descriptor kind found."); | |
| 156 | } | |
| 157 | ||
| 158 | getNextWord(descriptor, &descriptorWord); | |
| 159 | } | |
| 160 | ||
| 161 | return _URC_CONTINUE_UNWIND; | |
| 162 | } | |
| 163 | ||
| 164 | static _Unwind_Reason_Code unwindOneFrame(_Unwind_State state, | |
| 165 | _Unwind_Control_Block* ucbp, | |
| 166 | struct _Unwind_Context* context) { | |
| 167 | // Read the compact model EHT entry's header # 6.3 | |
| 168 | const uint32_t* unwindingData = ucbp->pr_cache.ehtp; | |
| 169 | assert((*unwindingData & 0xf0000000) == 0x80000000 && "Must be a compact entry"); | |
| 170 | Descriptor::Format format = | |
| 171 | static_cast<Descriptor::Format>((*unwindingData & 0x0f000000) >> 24); | |
| 172 | ||
| 173 | const char *lsda = | |
| 174 | reinterpret_cast<const char *>(_Unwind_GetLanguageSpecificData(context)); | |
| 175 | ||
| 176 | // Handle descriptors before unwinding so they are processed in the context | |
| 177 | // of the correct stack frame. | |
| 178 | _Unwind_Reason_Code result = | |
| 179 | ProcessDescriptors(state, ucbp, context, format, lsda, | |
| 180 | ucbp->pr_cache.additional); | |
| 181 | ||
| 182 | if (result != _URC_CONTINUE_UNWIND) | |
| 183 | return result; | |
| 184 | ||
| 185 | if (unw_step(reinterpret_cast<unw_cursor_t*>(context)) != UNW_STEP_SUCCESS) | |
| 186 | return _URC_FAILURE; | |
| 187 | return _URC_CONTINUE_UNWIND; | |
| 188 | } | |
| 189 | ||
| 190 | // Generates mask discriminator for _Unwind_VRS_Pop, e.g. for _UVRSC_CORE / | |
| 191 | // _UVRSD_UINT32. | |
| 192 | uint32_t RegisterMask(uint8_t start, uint8_t count_minus_one) { | |
| 193 | return ((1U << (count_minus_one + 1)) - 1) << start; | |
| 194 | } | |
| 195 | ||
| 196 | // Generates mask discriminator for _Unwind_VRS_Pop, e.g. for _UVRSC_VFP / | |
| 197 | // _UVRSD_DOUBLE. | |
| 198 | uint32_t RegisterRange(uint8_t start, uint8_t count_minus_one) { | |
| 199 | return ((uint32_t)start << 16) | ((uint32_t)count_minus_one + 1); | |
| 200 | } | |
| 201 | ||
| 202 | } // end anonymous namespace | |
| 203 | ||
| 204 | /** | |
| 205 | * Decodes an EHT entry. | |
| 206 | * | |
| 207 | * @param data Pointer to EHT. | |
| 208 | * @param[out] off Offset from return value (in bytes) to begin interpretation. | |
| 209 | * @param[out] len Number of bytes in unwind code. | |
| 210 | * @return Pointer to beginning of unwind code. | |
| 211 | */ | |
| 212 | extern "C" const uint32_t* | |
| 213 | decode_eht_entry(const uint32_t* data, size_t* off, size_t* len) { | |
| 214 | if ((*data & 0x80000000) == 0) { | |
| 215 | // 6.2: Generic Model | |
| 216 | // | |
| 217 | // EHT entry is a prel31 pointing to the PR, followed by data understood | |
| 218 | // only by the personality routine. Fortunately, all existing assembler | |
| 219 | // implementations, including GNU assembler, LLVM integrated assembler, | |
| 220 | // and ARM assembler, assume that the unwind opcodes come after the | |
| 221 | // personality rountine address. | |
| 222 | *off = 1; // First byte is size data. | |
| 223 | *len = (((data[1] >> 24) & 0xff) + 1) * 4; | |
| 224 | data++; // Skip the first word, which is the prel31 offset. | |
| 225 | } else { | |
| 226 | // 6.3: ARM Compact Model | |
| 227 | // | |
| 228 | // EHT entries here correspond to the __aeabi_unwind_cpp_pr[012] PRs indeded | |
| 229 | // by format: | |
| 230 | Descriptor::Format format = | |
| 231 | static_cast<Descriptor::Format>((*data & 0x0f000000) >> 24); | |
| 232 | switch (format) { | |
| 233 | case Descriptor::SU16: | |
| 234 | *len = 4; | |
| 235 | *off = 1; | |
| 236 | break; | |
| 237 | case Descriptor::LU16: | |
| 238 | case Descriptor::LU32: | |
| 239 | *len = 4 + 4 * ((*data & 0x00ff0000) >> 16); | |
| 240 | *off = 2; | |
| 241 | break; | |
| 242 | default: | |
| 243 | return nullptr; | |
| 244 | } | |
| 245 | } | |
| 246 | return data; | |
| 247 | } | |
| 248 | ||
| 249 | _LIBUNWIND_EXPORT _Unwind_Reason_Code | |
| 250 | _Unwind_VRS_Interpret(_Unwind_Context *context, const uint32_t *data, | |
| 251 | size_t offset, size_t len) { | |
| 252 | bool wrotePC = false; | |
| 253 | bool finish = false; | |
| 254 | while (offset < len && !finish) { | |
| 255 | uint8_t byte = getByte(data, offset++); | |
| 256 | if ((byte & 0x80) == 0) { | |
| 257 | uint32_t sp; | |
| 258 | _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp); | |
| 259 | if (byte & 0x40) | |
| 260 | sp -= (((uint32_t)byte & 0x3f) << 2) + 4; | |
| 261 | else | |
| 262 | sp += ((uint32_t)byte << 2) + 4; | |
| 263 | _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp); | |
| 264 | } else { | |
| 265 | switch (byte & 0xf0) { | |
| 266 | case 0x80: { | |
| 267 | if (offset >= len) | |
| 268 | return _URC_FAILURE; | |
| 269 | uint32_t registers = | |
| 270 | (((uint32_t)byte & 0x0f) << 12) | | |
| 271 | (((uint32_t)getByte(data, offset++)) << 4); | |
| 272 | if (!registers) | |
| 273 | return _URC_FAILURE; | |
| 274 | if (registers & (1 << 15)) | |
| 275 | wrotePC = true; | |
| 276 | _Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32); | |
| 277 | break; | |
| 278 | } | |
| 279 | case 0x90: { | |
| 280 | uint8_t reg = byte & 0x0f; | |
| 281 | if (reg == 13 || reg == 15) | |
| 282 | return _URC_FAILURE; | |
| 283 | uint32_t sp; | |
| 284 | _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_R0 + reg, | |
| 285 | _UVRSD_UINT32, &sp); | |
| 286 | _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, | |
| 287 | &sp); | |
| 288 | break; | |
| 289 | } | |
| 290 | case 0xa0: { | |
| 291 | uint32_t registers = RegisterMask(4, byte & 0x07); | |
| 292 | if (byte & 0x08) | |
| 293 | registers |= 1 << 14; | |
| 294 | _Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32); | |
| 295 | break; | |
| 296 | } | |
| 297 | case 0xb0: { | |
| 298 | switch (byte) { | |
| 299 | case 0xb0: | |
| 300 | finish = true; | |
| 301 | break; | |
| 302 | case 0xb1: { | |
| 303 | if (offset >= len) | |
| 304 | return _URC_FAILURE; | |
| 305 | uint8_t registers = getByte(data, offset++); | |
| 306 | if (registers & 0xf0 || !registers) | |
| 307 | return _URC_FAILURE; | |
| 308 | _Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32); | |
| 309 | break; | |
| 310 | } | |
| 311 | case 0xb2: { | |
| 312 | uint32_t addend = 0; | |
| 313 | uint32_t shift = 0; | |
| 314 | // This decodes a uleb128 value. | |
| 315 | while (true) { | |
| 316 | if (offset >= len) | |
| 317 | return _URC_FAILURE; | |
| 318 | uint32_t v = getByte(data, offset++); | |
| 319 | addend |= (v & 0x7f) << shift; | |
| 320 | if ((v & 0x80) == 0) | |
| 321 | break; | |
| 322 | shift += 7; | |
| 323 | } | |
| 324 | uint32_t sp; | |
| 325 | _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, | |
| 326 | &sp); | |
| 327 | sp += 0x204 + (addend << 2); | |
| 328 | _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, | |
| 329 | &sp); | |
| 330 | break; | |
| 331 | } | |
| 332 | case 0xb3: { | |
| 333 | uint8_t v = getByte(data, offset++); | |
| 334 | _Unwind_VRS_Pop(context, _UVRSC_VFP, | |
| 335 | RegisterRange(static_cast<uint8_t>(v >> 4), | |
| 336 | v & 0x0f), _UVRSD_VFPX); | |
| 337 | break; | |
| 338 | } | |
| 339 | case 0xb4: | |
| 340 | case 0xb5: | |
| 341 | case 0xb6: | |
| 342 | case 0xb7: | |
| 343 | return _URC_FAILURE; | |
| 344 | default: | |
| 345 | _Unwind_VRS_Pop(context, _UVRSC_VFP, | |
| 346 | RegisterRange(8, byte & 0x07), _UVRSD_VFPX); | |
| 347 | break; | |
| 348 | } | |
| 349 | break; | |
| 350 | } | |
| 351 | case 0xc0: { | |
| 352 | switch (byte) { | |
| 353 | #if defined(__ARM_WMMX) | |
| 354 | case 0xc0: | |
| 355 | case 0xc1: | |
| 356 | case 0xc2: | |
| 357 | case 0xc3: | |
| 358 | case 0xc4: | |
| 359 | case 0xc5: | |
| 360 | _Unwind_VRS_Pop(context, _UVRSC_WMMXD, | |
| 361 | RegisterRange(10, byte & 0x7), _UVRSD_DOUBLE); | |
| 362 | break; | |
| 363 | case 0xc6: { | |
| 364 | uint8_t v = getByte(data, offset++); | |
| 365 | uint8_t start = static_cast<uint8_t>(v >> 4); | |
| 366 | uint8_t count_minus_one = v & 0xf; | |
| 367 | if (start + count_minus_one >= 16) | |
| 368 | return _URC_FAILURE; | |
| 369 | _Unwind_VRS_Pop(context, _UVRSC_WMMXD, | |
| 370 | RegisterRange(start, count_minus_one), | |
| 371 | _UVRSD_DOUBLE); | |
| 372 | break; | |
| 373 | } | |
| 374 | case 0xc7: { | |
| 375 | uint8_t v = getByte(data, offset++); | |
| 376 | if (!v || v & 0xf0) | |
| 377 | return _URC_FAILURE; | |
| 378 | _Unwind_VRS_Pop(context, _UVRSC_WMMXC, v, _UVRSD_DOUBLE); | |
| 379 | break; | |
| 380 | } | |
| 381 | #endif | |
| 382 | case 0xc8: | |
| 383 | case 0xc9: { | |
| 384 | uint8_t v = getByte(data, offset++); | |
| 385 | uint8_t start = | |
| 386 | static_cast<uint8_t>(((byte == 0xc8) ? 16 : 0) + (v >> 4)); | |
| 387 | uint8_t count_minus_one = v & 0xf; | |
| 388 | if (start + count_minus_one >= 32) | |
| 389 | return _URC_FAILURE; | |
| 390 | _Unwind_VRS_Pop(context, _UVRSC_VFP, | |
| 391 | RegisterRange(start, count_minus_one), | |
| 392 | _UVRSD_DOUBLE); | |
| 393 | break; | |
| 394 | } | |
| 395 | default: | |
| 396 | return _URC_FAILURE; | |
| 397 | } | |
| 398 | break; | |
| 399 | } | |
| 400 | case 0xd0: { | |
| 401 | if (byte & 0x08) | |
| 402 | return _URC_FAILURE; | |
| 403 | _Unwind_VRS_Pop(context, _UVRSC_VFP, RegisterRange(8, byte & 0x7), | |
| 404 | _UVRSD_DOUBLE); | |
| 405 | break; | |
| 406 | } | |
| 407 | default: | |
| 408 | return _URC_FAILURE; | |
| 409 | } | |
| 410 | } | |
| 411 | } | |
| 412 | if (!wrotePC) { | |
| 413 | uint32_t lr; | |
| 414 | _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_LR, _UVRSD_UINT32, &lr); | |
| 415 | _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_IP, _UVRSD_UINT32, &lr); | |
| 416 | } | |
| 417 | return _URC_CONTINUE_UNWIND; | |
| 418 | } | |
| 419 | ||
| 420 | extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code | |
| 421 | __aeabi_unwind_cpp_pr0(_Unwind_State state, _Unwind_Control_Block *ucbp, | |
| 422 | _Unwind_Context *context) { | |
| 423 | return unwindOneFrame(state, ucbp, context); | |
| 424 | } | |
| 425 | ||
| 426 | extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code | |
| 427 | __aeabi_unwind_cpp_pr1(_Unwind_State state, _Unwind_Control_Block *ucbp, | |
| 428 | _Unwind_Context *context) { | |
| 429 | return unwindOneFrame(state, ucbp, context); | |
| 430 | } | |
| 431 | ||
| 432 | extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code | |
| 433 | __aeabi_unwind_cpp_pr2(_Unwind_State state, _Unwind_Control_Block *ucbp, | |
| 434 | _Unwind_Context *context) { | |
| 435 | return unwindOneFrame(state, ucbp, context); | |
| 436 | } | |
| 437 | ||
| 438 | static _Unwind_Reason_Code | |
| 439 | unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) { | |
| 440 | // EHABI #7.3 discusses preserving the VRS in a "temporary VRS" during | |
| 441 | // phase 1 and then restoring it to the "primary VRS" for phase 2. The | |
| 442 | // effect is phase 2 doesn't see any of the VRS manipulations from phase 1. | |
| 443 | // In this implementation, the phases don't share the VRS backing store. | |
| 444 | // Instead, they are passed the original |uc| and they create a new VRS | |
| 445 | // from scratch thus achieving the same effect. | |
| 446 | unw_init_local(cursor, uc); | |
| 447 | ||
| 448 | // Walk each frame looking for a place to stop. | |
| 449 | for (bool handlerNotFound = true; handlerNotFound;) { | |
| 450 | ||
| 451 | // See if frame has code to run (has personality routine). | |
| 452 | unw_proc_info_t frameInfo; | |
| 453 | if (unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { | |
| 454 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_get_proc_info " | |
| 455 | "failed => _URC_FATAL_PHASE1_ERROR", | |
| 456 | static_cast<void *>(exception_object)); | |
| 457 | return _URC_FATAL_PHASE1_ERROR; | |
| 458 | } | |
| 459 | ||
| 460 | // When tracing, print state information. | |
| 461 | if (_LIBUNWIND_TRACING_UNWINDING) { | |
| 462 | char functionBuf[512]; | |
| 463 | const char *functionName = functionBuf; | |
| 464 | unw_word_t offset; | |
| 465 | if ((unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), | |
| 466 | &offset) != UNW_ESUCCESS) || | |
| 467 | (frameInfo.start_ip + offset > frameInfo.end_ip)) | |
| 468 | functionName = ".anonymous."; | |
| 469 | unw_word_t pc; | |
| 470 | unw_get_reg(cursor, UNW_REG_IP, &pc); | |
| 471 | _LIBUNWIND_TRACE_UNWINDING( | |
| 472 | "unwind_phase1(ex_ojb=%p): pc=0x%" PRIxPTR ", start_ip=0x%" PRIxPTR ", func=%s, " | |
| 473 | "lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR, | |
| 474 | static_cast<void *>(exception_object), pc, | |
| 475 | frameInfo.start_ip, functionName, | |
| 476 | frameInfo.lsda, frameInfo.handler); | |
| 477 | } | |
| 478 | ||
| 479 | // If there is a personality routine, ask it if it will want to stop at | |
| 480 | // this frame. | |
| 481 | if (frameInfo.handler != 0) { | |
| 482 | __personality_routine p = | |
| 483 | (__personality_routine)(long)(frameInfo.handler); | |
| 484 | _LIBUNWIND_TRACE_UNWINDING( | |
| 485 | "unwind_phase1(ex_ojb=%p): calling personality function %p", | |
| 486 | static_cast<void *>(exception_object), | |
| 487 | reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(p))); | |
| 488 | struct _Unwind_Context *context = (struct _Unwind_Context *)(cursor); | |
| 489 | exception_object->pr_cache.fnstart = frameInfo.start_ip; | |
| 490 | exception_object->pr_cache.ehtp = | |
| 491 | (_Unwind_EHT_Header *)frameInfo.unwind_info; | |
| 492 | exception_object->pr_cache.additional = frameInfo.flags; | |
| 493 | _Unwind_Reason_Code personalityResult = | |
| 494 | (*p)(_US_VIRTUAL_UNWIND_FRAME, exception_object, context); | |
| 495 | _LIBUNWIND_TRACE_UNWINDING( | |
| 496 | "unwind_phase1(ex_ojb=%p): personality result %d start_ip %x ehtp %p " | |
| 497 | "additional %x", | |
| 498 | static_cast<void *>(exception_object), personalityResult, | |
| 499 | exception_object->pr_cache.fnstart, | |
| 500 | static_cast<void *>(exception_object->pr_cache.ehtp), | |
| 501 | exception_object->pr_cache.additional); | |
| 502 | switch (personalityResult) { | |
| 503 | case _URC_HANDLER_FOUND: | |
| 504 | // found a catch clause or locals that need destructing in this frame | |
| 505 | // stop search and remember stack pointer at the frame | |
| 506 | handlerNotFound = false; | |
| 507 | // p should have initialized barrier_cache. EHABI #7.3.5 | |
| 508 | _LIBUNWIND_TRACE_UNWINDING( | |
| 509 | "unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND", | |
| 510 | static_cast<void *>(exception_object)); | |
| 511 | return _URC_NO_REASON; | |
| 512 | ||
| 513 | case _URC_CONTINUE_UNWIND: | |
| 514 | _LIBUNWIND_TRACE_UNWINDING( | |
| 515 | "unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND", | |
| 516 | static_cast<void *>(exception_object)); | |
| 517 | // continue unwinding | |
| 518 | break; | |
| 519 | ||
| 520 | // EHABI #7.3.3 | |
| 521 | case _URC_FAILURE: | |
| 522 | return _URC_FAILURE; | |
| 523 | ||
| 524 | default: | |
| 525 | // something went wrong | |
| 526 | _LIBUNWIND_TRACE_UNWINDING( | |
| 527 | "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR", | |
| 528 | static_cast<void *>(exception_object)); | |
| 529 | return _URC_FATAL_PHASE1_ERROR; | |
| 530 | } | |
| 531 | } | |
| 532 | } | |
| 533 | return _URC_NO_REASON; | |
| 534 | } | |
| 535 | ||
| 536 | static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, | |
| 537 | _Unwind_Exception *exception_object, | |
| 538 | bool resume) { | |
| 539 | // See comment at the start of unwind_phase1 regarding VRS integrity. | |
| 540 | unw_init_local(cursor, uc); | |
| 541 | ||
| 542 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)", | |
| 543 | static_cast<void *>(exception_object)); | |
| 544 | int frame_count = 0; | |
| 545 | ||
| 546 | // Walk each frame until we reach where search phase said to stop. | |
| 547 | while (true) { | |
| 548 | // Ask libunwind to get next frame (skip over first which is | |
| 549 | // _Unwind_RaiseException or _Unwind_Resume). | |
| 550 | // | |
| 551 | // Resume only ever makes sense for 1 frame. | |
| 552 | _Unwind_State state = | |
| 553 | resume ? _US_UNWIND_FRAME_RESUME : _US_UNWIND_FRAME_STARTING; | |
| 554 | if (resume && frame_count == 1) { | |
| 555 | // On a resume, first unwind the _Unwind_Resume() frame. The next frame | |
| 556 | // is now the landing pad for the cleanup from a previous execution of | |
| 557 | // phase2. To continue unwindingly correctly, replace VRS[15] with the | |
| 558 | // IP of the frame that the previous run of phase2 installed the context | |
| 559 | // for. After this, continue unwinding as if normal. | |
| 560 | // | |
| 561 | // See #7.4.6 for details. | |
| 562 | unw_set_reg(cursor, UNW_REG_IP, | |
| 563 | exception_object->unwinder_cache.reserved2); | |
| 564 | resume = false; | |
| 565 | } | |
| 566 | ||
| 567 | // Get info about this frame. | |
| 568 | unw_word_t sp; | |
| 569 | unw_proc_info_t frameInfo; | |
| 570 | unw_get_reg(cursor, UNW_REG_SP, &sp); | |
| 571 | if (unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { | |
| 572 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_get_proc_info " | |
| 573 | "failed => _URC_FATAL_PHASE2_ERROR", | |
| 574 | static_cast<void *>(exception_object)); | |
| 575 | return _URC_FATAL_PHASE2_ERROR; | |
| 576 | } | |
| 577 | ||
| 578 | // When tracing, print state information. | |
| 579 | if (_LIBUNWIND_TRACING_UNWINDING) { | |
| 580 | char functionBuf[512]; | |
| 581 | const char *functionName = functionBuf; | |
| 582 | unw_word_t offset; | |
| 583 | if ((unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), | |
| 584 | &offset) != UNW_ESUCCESS) || | |
| 585 | (frameInfo.start_ip + offset > frameInfo.end_ip)) | |
| 586 | functionName = ".anonymous."; | |
| 587 | _LIBUNWIND_TRACE_UNWINDING( | |
| 588 | "unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIxPTR ", func=%s, sp=0x%" PRIxPTR ", " | |
| 589 | "lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR "", | |
| 590 | static_cast<void *>(exception_object), frameInfo.start_ip, | |
| 591 | functionName, sp, frameInfo.lsda, | |
| 592 | frameInfo.handler); | |
| 593 | } | |
| 594 | ||
| 595 | // If there is a personality routine, tell it we are unwinding. | |
| 596 | if (frameInfo.handler != 0) { | |
| 597 | __personality_routine p = | |
| 598 | (__personality_routine)(long)(frameInfo.handler); | |
| 599 | struct _Unwind_Context *context = (struct _Unwind_Context *)(cursor); | |
| 600 | // EHABI #7.2 | |
| 601 | exception_object->pr_cache.fnstart = frameInfo.start_ip; | |
| 602 | exception_object->pr_cache.ehtp = | |
| 603 | (_Unwind_EHT_Header *)frameInfo.unwind_info; | |
| 604 | exception_object->pr_cache.additional = frameInfo.flags; | |
| 605 | _Unwind_Reason_Code personalityResult = | |
| 606 | (*p)(state, exception_object, context); | |
| 607 | switch (personalityResult) { | |
| 608 | case _URC_CONTINUE_UNWIND: | |
| 609 | // Continue unwinding | |
| 610 | _LIBUNWIND_TRACE_UNWINDING( | |
| 611 | "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND", | |
| 612 | static_cast<void *>(exception_object)); | |
| 613 | // EHABI #7.2 | |
| 614 | if (sp == exception_object->barrier_cache.sp) { | |
| 615 | // Phase 1 said we would stop at this frame, but we did not... | |
| 616 | _LIBUNWIND_ABORT("during phase1 personality function said it would " | |
| 617 | "stop here, but now in phase2 it did not stop here"); | |
| 618 | } | |
| 619 | break; | |
| 620 | case _URC_INSTALL_CONTEXT: | |
| 621 | _LIBUNWIND_TRACE_UNWINDING( | |
| 622 | "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT", | |
| 623 | static_cast<void *>(exception_object)); | |
| 624 | // Personality routine says to transfer control to landing pad. | |
| 625 | // We may get control back if landing pad calls _Unwind_Resume(). | |
| 626 | if (_LIBUNWIND_TRACING_UNWINDING) { | |
| 627 | unw_word_t pc; | |
| 628 | unw_get_reg(cursor, UNW_REG_IP, &pc); | |
| 629 | unw_get_reg(cursor, UNW_REG_SP, &sp); | |
| 630 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering " | |
| 631 | "user code with ip=0x%" PRIxPTR ", sp=0x%" PRIxPTR, | |
| 632 | static_cast<void *>(exception_object), | |
| 633 | pc, sp); | |
| 634 | } | |
| 635 | ||
| 636 | { | |
| 637 | // EHABI #7.4.1 says we need to preserve pc for when _Unwind_Resume | |
| 638 | // is called back, to find this same frame. | |
| 639 | unw_word_t pc; | |
| 640 | unw_get_reg(cursor, UNW_REG_IP, &pc); | |
| 641 | exception_object->unwinder_cache.reserved2 = (uint32_t)pc; | |
| 642 | } | |
| 643 | unw_resume(cursor); | |
| 644 | // unw_resume() only returns if there was an error. | |
| 645 | return _URC_FATAL_PHASE2_ERROR; | |
| 646 | ||
| 647 | // # EHABI #7.4.3 | |
| 648 | case _URC_FAILURE: | |
| 649 | abort(); | |
| 650 | ||
| 651 | default: | |
| 652 | // Personality routine returned an unknown result code. | |
| 653 | _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d", | |
| 654 | personalityResult); | |
| 655 | return _URC_FATAL_PHASE2_ERROR; | |
| 656 | } | |
| 657 | } | |
| 658 | frame_count++; | |
| 659 | } | |
| 660 | ||
| 661 | // Clean up phase did not resume at the frame that the search phase | |
| 662 | // said it would... | |
| 663 | return _URC_FATAL_PHASE2_ERROR; | |
| 664 | } | |
| 665 | ||
| 666 | /// Called by __cxa_throw. Only returns if there is a fatal error. | |
| 667 | _LIBUNWIND_EXPORT _Unwind_Reason_Code | |
| 668 | _Unwind_RaiseException(_Unwind_Exception *exception_object) { | |
| 669 | _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)", | |
| 670 | static_cast<void *>(exception_object)); | |
| 671 | unw_context_t uc; | |
| 672 | unw_cursor_t cursor; | |
| 673 | unw_getcontext(&uc); | |
| 674 | ||
| 675 | // This field for is for compatibility with GCC to say this isn't a forced | |
| 676 | // unwind. EHABI #7.2 | |
| 677 | exception_object->unwinder_cache.reserved1 = 0; | |
| 678 | ||
| 679 | // phase 1: the search phase | |
| 680 | _Unwind_Reason_Code phase1 = unwind_phase1(&uc, &cursor, exception_object); | |
| 681 | if (phase1 != _URC_NO_REASON) | |
| 682 | return phase1; | |
| 683 | ||
| 684 | // phase 2: the clean up phase | |
| 685 | return unwind_phase2(&uc, &cursor, exception_object, false); | |
| 686 | } | |
| 687 | ||
| 688 | _LIBUNWIND_EXPORT void _Unwind_Complete(_Unwind_Exception* exception_object) { | |
| 689 | // This is to be called when exception handling completes to give us a chance | |
| 690 | // to perform any housekeeping. EHABI #7.2. But we have nothing to do here. | |
| 691 | (void)exception_object; | |
| 692 | } | |
| 693 | ||
| 694 | /// When _Unwind_RaiseException() is in phase2, it hands control | |
| 695 | /// to the personality function at each frame. The personality | |
| 696 | /// may force a jump to a landing pad in that function, the landing | |
| 697 | /// pad code may then call _Unwind_Resume() to continue with the | |
| 698 | /// unwinding. Note: the call to _Unwind_Resume() is from compiler | |
| 699 | /// geneated user code. All other _Unwind_* routines are called | |
| 700 | /// by the C++ runtime __cxa_* routines. | |
| 701 | /// | |
| 702 | /// Note: re-throwing an exception (as opposed to continuing the unwind) | |
| 703 | /// is implemented by having the code call __cxa_rethrow() which | |
| 704 | /// in turn calls _Unwind_Resume_or_Rethrow(). | |
| 705 | _LIBUNWIND_EXPORT void | |
| 706 | _Unwind_Resume(_Unwind_Exception *exception_object) { | |
| 707 | _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)", | |
| 708 | static_cast<void *>(exception_object)); | |
| 709 | unw_context_t uc; | |
| 710 | unw_cursor_t cursor; | |
| 711 | unw_getcontext(&uc); | |
| 712 | ||
| 713 | // _Unwind_RaiseException on EHABI will always set the reserved1 field to 0, | |
| 714 | // which is in the same position as private_1 below. | |
| 715 | // TODO(ajwong): Who wronte the above? Why is it true? | |
| 716 | unwind_phase2(&uc, &cursor, exception_object, true); | |
| 717 | ||
| 718 | // Clients assume _Unwind_Resume() does not return, so all we can do is abort. | |
| 719 | _LIBUNWIND_ABORT("_Unwind_Resume() can't return"); | |
| 720 | } | |
| 721 | ||
| 722 | /// Called by personality handler during phase 2 to get LSDA for current frame. | |
| 723 | _LIBUNWIND_EXPORT uintptr_t | |
| 724 | _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { | |
| 725 | unw_cursor_t *cursor = (unw_cursor_t *)context; | |
| 726 | unw_proc_info_t frameInfo; | |
| 727 | uintptr_t result = 0; | |
| 728 | if (unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) | |
| 729 | result = (uintptr_t)frameInfo.lsda; | |
| 730 | _LIBUNWIND_TRACE_API( | |
| 731 | "_Unwind_GetLanguageSpecificData(context=%p) => 0x%llx", | |
| 732 | static_cast<void *>(context), (long long)result); | |
| 733 | return result; | |
| 734 | } | |
| 735 | ||
| 736 | static uint64_t ValueAsBitPattern(_Unwind_VRS_DataRepresentation representation, | |
| 737 | void* valuep) { | |
| 738 | uint64_t value = 0; | |
| 739 | switch (representation) { | |
| 740 | case _UVRSD_UINT32: | |
| 741 | case _UVRSD_FLOAT: | |
| 742 | memcpy(&value, valuep, sizeof(uint32_t)); | |
| 743 | break; | |
| 744 | ||
| 745 | case _UVRSD_VFPX: | |
| 746 | case _UVRSD_UINT64: | |
| 747 | case _UVRSD_DOUBLE: | |
| 748 | memcpy(&value, valuep, sizeof(uint64_t)); | |
| 749 | break; | |
| 750 | } | |
| 751 | return value; | |
| 752 | } | |
| 753 | ||
| 754 | _LIBUNWIND_EXPORT _Unwind_VRS_Result | |
| 755 | _Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, | |
| 756 | uint32_t regno, _Unwind_VRS_DataRepresentation representation, | |
| 757 | void *valuep) { | |
| 758 | _LIBUNWIND_TRACE_API("_Unwind_VRS_Set(context=%p, regclass=%d, reg=%d, " | |
| 759 | "rep=%d, value=0x%llX)", | |
| 760 | static_cast<void *>(context), regclass, regno, | |
| 761 | representation, | |
| 762 | ValueAsBitPattern(representation, valuep)); | |
| 763 | unw_cursor_t *cursor = (unw_cursor_t *)context; | |
| 764 | switch (regclass) { | |
| 765 | case _UVRSC_CORE: | |
| 766 | if (representation != _UVRSD_UINT32 || regno > 15) | |
| 767 | return _UVRSR_FAILED; | |
| 768 | return unw_set_reg(cursor, (unw_regnum_t)(UNW_ARM_R0 + regno), | |
| 769 | *(unw_word_t *)valuep) == UNW_ESUCCESS | |
| 770 | ? _UVRSR_OK | |
| 771 | : _UVRSR_FAILED; | |
| 772 | case _UVRSC_VFP: | |
| 773 | if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) | |
| 774 | return _UVRSR_FAILED; | |
| 775 | if (representation == _UVRSD_VFPX) { | |
| 776 | // Can only touch d0-15 with FSTMFDX. | |
| 777 | if (regno > 15) | |
| 778 | return _UVRSR_FAILED; | |
| 779 | unw_save_vfp_as_X(cursor); | |
| 780 | } else { | |
| 781 | if (regno > 31) | |
| 782 | return _UVRSR_FAILED; | |
| 783 | } | |
| 784 | return unw_set_fpreg(cursor, (unw_regnum_t)(UNW_ARM_D0 + regno), | |
| 785 | *(unw_fpreg_t *)valuep) == UNW_ESUCCESS | |
| 786 | ? _UVRSR_OK | |
| 787 | : _UVRSR_FAILED; | |
| 788 | #if defined(__ARM_WMMX) | |
| 789 | case _UVRSC_WMMXC: | |
| 790 | if (representation != _UVRSD_UINT32 || regno > 3) | |
| 791 | return _UVRSR_FAILED; | |
| 792 | return unw_set_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno), | |
| 793 | *(unw_word_t *)valuep) == UNW_ESUCCESS | |
| 794 | ? _UVRSR_OK | |
| 795 | : _UVRSR_FAILED; | |
| 796 | case _UVRSC_WMMXD: | |
| 797 | if (representation != _UVRSD_DOUBLE || regno > 31) | |
| 798 | return _UVRSR_FAILED; | |
| 799 | return unw_set_fpreg(cursor, (unw_regnum_t)(UNW_ARM_WR0 + regno), | |
| 800 | *(unw_fpreg_t *)valuep) == UNW_ESUCCESS | |
| 801 | ? _UVRSR_OK | |
| 802 | : _UVRSR_FAILED; | |
| 803 | #else | |
| 804 | case _UVRSC_WMMXC: | |
| 805 | case _UVRSC_WMMXD: | |
| 806 | break; | |
| 807 | #endif | |
| 808 | } | |
| 809 | _LIBUNWIND_ABORT("unsupported register class"); | |
| 810 | } | |
| 811 | ||
| 812 | static _Unwind_VRS_Result | |
| 813 | _Unwind_VRS_Get_Internal(_Unwind_Context *context, | |
| 814 | _Unwind_VRS_RegClass regclass, uint32_t regno, | |
| 815 | _Unwind_VRS_DataRepresentation representation, | |
| 816 | void *valuep) { | |
| 817 | unw_cursor_t *cursor = (unw_cursor_t *)context; | |
| 818 | switch (regclass) { | |
| 819 | case _UVRSC_CORE: | |
| 820 | if (representation != _UVRSD_UINT32 || regno > 15) | |
| 821 | return _UVRSR_FAILED; | |
| 822 | return unw_get_reg(cursor, (unw_regnum_t)(UNW_ARM_R0 + regno), | |
| 823 | (unw_word_t *)valuep) == UNW_ESUCCESS | |
| 824 | ? _UVRSR_OK | |
| 825 | : _UVRSR_FAILED; | |
| 826 | case _UVRSC_VFP: | |
| 827 | if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) | |
| 828 | return _UVRSR_FAILED; | |
| 829 | if (representation == _UVRSD_VFPX) { | |
| 830 | // Can only touch d0-15 with FSTMFDX. | |
| 831 | if (regno > 15) | |
| 832 | return _UVRSR_FAILED; | |
| 833 | unw_save_vfp_as_X(cursor); | |
| 834 | } else { | |
| 835 | if (regno > 31) | |
| 836 | return _UVRSR_FAILED; | |
| 837 | } | |
| 838 | return unw_get_fpreg(cursor, (unw_regnum_t)(UNW_ARM_D0 + regno), | |
| 839 | (unw_fpreg_t *)valuep) == UNW_ESUCCESS | |
| 840 | ? _UVRSR_OK | |
| 841 | : _UVRSR_FAILED; | |
| 842 | #if defined(__ARM_WMMX) | |
| 843 | case _UVRSC_WMMXC: | |
| 844 | if (representation != _UVRSD_UINT32 || regno > 3) | |
| 845 | return _UVRSR_FAILED; | |
| 846 | return unw_get_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno), | |
| 847 | (unw_word_t *)valuep) == UNW_ESUCCESS | |
| 848 | ? _UVRSR_OK | |
| 849 | : _UVRSR_FAILED; | |
| 850 | case _UVRSC_WMMXD: | |
| 851 | if (representation != _UVRSD_DOUBLE || regno > 31) | |
| 852 | return _UVRSR_FAILED; | |
| 853 | return unw_get_fpreg(cursor, (unw_regnum_t)(UNW_ARM_WR0 + regno), | |
| 854 | (unw_fpreg_t *)valuep) == UNW_ESUCCESS | |
| 855 | ? _UVRSR_OK | |
| 856 | : _UVRSR_FAILED; | |
| 857 | #else | |
| 858 | case _UVRSC_WMMXC: | |
| 859 | case _UVRSC_WMMXD: | |
| 860 | break; | |
| 861 | #endif | |
| 862 | } | |
| 863 | _LIBUNWIND_ABORT("unsupported register class"); | |
| 864 | } | |
| 865 | ||
| 866 | _LIBUNWIND_EXPORT _Unwind_VRS_Result | |
| 867 | _Unwind_VRS_Get(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, | |
| 868 | uint32_t regno, _Unwind_VRS_DataRepresentation representation, | |
| 869 | void *valuep) { | |
| 870 | _Unwind_VRS_Result result = | |
| 871 | _Unwind_VRS_Get_Internal(context, regclass, regno, representation, | |
| 872 | valuep); | |
| 873 | _LIBUNWIND_TRACE_API("_Unwind_VRS_Get(context=%p, regclass=%d, reg=%d, " | |
| 874 | "rep=%d, value=0x%llX, result = %d)", | |
| 875 | static_cast<void *>(context), regclass, regno, | |
| 876 | representation, | |
| 877 | ValueAsBitPattern(representation, valuep), result); | |
| 878 | return result; | |
| 879 | } | |
| 880 | ||
| 881 | _Unwind_VRS_Result | |
| 882 | _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, | |
| 883 | uint32_t discriminator, | |
| 884 | _Unwind_VRS_DataRepresentation representation) { | |
| 885 | _LIBUNWIND_TRACE_API("_Unwind_VRS_Pop(context=%p, regclass=%d, " | |
| 886 | "discriminator=%d, representation=%d)", | |
| 887 | static_cast<void *>(context), regclass, discriminator, | |
| 888 | representation); | |
| 889 | switch (regclass) { | |
| 890 | case _UVRSC_WMMXC: | |
| 891 | #if !defined(__ARM_WMMX) | |
| 892 | break; | |
| 893 | #endif | |
| 894 | case _UVRSC_CORE: { | |
| 895 | if (representation != _UVRSD_UINT32) | |
| 896 | return _UVRSR_FAILED; | |
| 897 | // When popping SP from the stack, we don't want to override it from the | |
| 898 | // computed new stack location. See EHABI #7.5.4 table 3. | |
| 899 | bool poppedSP = false; | |
| 900 | uint32_t* sp; | |
| 901 | if (_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, | |
| 902 | _UVRSD_UINT32, &sp) != _UVRSR_OK) { | |
| 903 | return _UVRSR_FAILED; | |
| 904 | } | |
| 905 | for (uint32_t i = 0; i < 16; ++i) { | |
| 906 | if (!(discriminator & static_cast<uint32_t>(1 << i))) | |
| 907 | continue; | |
| 908 | uint32_t value = *sp++; | |
| 909 | if (regclass == _UVRSC_CORE && i == 13) | |
| 910 | poppedSP = true; | |
| 911 | if (_Unwind_VRS_Set(context, regclass, i, | |
| 912 | _UVRSD_UINT32, &value) != _UVRSR_OK) { | |
| 913 | return _UVRSR_FAILED; | |
| 914 | } | |
| 915 | } | |
| 916 | if (!poppedSP) { | |
| 917 | return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, | |
| 918 | _UVRSD_UINT32, &sp); | |
| 919 | } | |
| 920 | return _UVRSR_OK; | |
| 921 | } | |
| 922 | case _UVRSC_WMMXD: | |
| 923 | #if !defined(__ARM_WMMX) | |
| 924 | break; | |
| 925 | #endif | |
| 926 | case _UVRSC_VFP: { | |
| 927 | if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) | |
| 928 | return _UVRSR_FAILED; | |
| 929 | uint32_t first = discriminator >> 16; | |
| 930 | uint32_t count = discriminator & 0xffff; | |
| 931 | uint32_t end = first+count; | |
| 932 | uint32_t* sp; | |
| 933 | if (_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, | |
| 934 | _UVRSD_UINT32, &sp) != _UVRSR_OK) { | |
| 935 | return _UVRSR_FAILED; | |
| 936 | } | |
| 937 | // For _UVRSD_VFPX, we're assuming the data is stored in FSTMX "standard | |
| 938 | // format 1", which is equivalent to FSTMD + a padding word. | |
| 939 | for (uint32_t i = first; i < end; ++i) { | |
| 940 | // SP is only 32-bit aligned so don't copy 64-bit at a time. | |
| 941 | uint64_t value = *sp++; | |
| 942 | value |= ((uint64_t)(*sp++)) << 32; | |
| 943 | if (_Unwind_VRS_Set(context, regclass, i, representation, &value) != | |
| 944 | _UVRSR_OK) | |
| 945 | return _UVRSR_FAILED; | |
| 946 | } | |
| 947 | if (representation == _UVRSD_VFPX) | |
| 948 | ++sp; | |
| 949 | return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, | |
| 950 | &sp); | |
| 951 | } | |
| 952 | } | |
| 953 | _LIBUNWIND_ABORT("unsupported register class"); | |
| 954 | } | |
| 955 | ||
| 956 | /// Called by personality handler during phase 2 to find the start of the | |
| 957 | /// function. | |
| 958 | _LIBUNWIND_EXPORT uintptr_t | |
| 959 | _Unwind_GetRegionStart(struct _Unwind_Context *context) { | |
| 960 | unw_cursor_t *cursor = (unw_cursor_t *)context; | |
| 961 | unw_proc_info_t frameInfo; | |
| 962 | uintptr_t result = 0; | |
| 963 | if (unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) | |
| 964 | result = (uintptr_t)frameInfo.start_ip; | |
| 965 | _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%llX", | |
| 966 | static_cast<void *>(context), (long long)result); | |
| 967 | return result; | |
| 968 | } | |
| 969 | ||
| 970 | ||
| 971 | /// Called by personality handler during phase 2 if a foreign exception | |
| 972 | // is caught. | |
| 973 | _LIBUNWIND_EXPORT void | |
| 974 | _Unwind_DeleteException(_Unwind_Exception *exception_object) { | |
| 975 | _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)", | |
| 976 | static_cast<void *>(exception_object)); | |
| 977 | if (exception_object->exception_cleanup != NULL) | |
| 978 | (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, | |
| 979 | exception_object); | |
| 980 | } | |
| 981 | ||
| 982 | extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code | |
| 983 | __gnu_unwind_frame(_Unwind_Exception *exception_object, | |
| 984 | struct _Unwind_Context *context) { | |
| 985 | unw_cursor_t *cursor = (unw_cursor_t *)context; | |
| 986 | if (unw_step(cursor) != UNW_STEP_SUCCESS) | |
| 987 | return _URC_FAILURE; | |
| 988 | return _URC_OK; | |
| 989 | } | |
| 990 | ||
| 991 | #endif // defined(_LIBUNWIND_ARM_EHABI) |
libunwind/src/Unwind-EHABI.h created+51| ... | ... | @@ -0,0 +1,51 @@ |
| 1 | //===------------------------- Unwind-EHABI.hpp ---------------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is dual licensed under the MIT and the University of Illinois Open | |
| 6 | // Source Licenses. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | // | |
| 9 | //===----------------------------------------------------------------------===// | |
| 10 | ||
| 11 | #ifndef __UNWIND_EHABI_H__ | |
| 12 | #define __UNWIND_EHABI_H__ | |
| 13 | ||
| 14 | #include <__libunwind_config.h> | |
| 15 | ||
| 16 | #if defined(_LIBUNWIND_ARM_EHABI) | |
| 17 | ||
| 18 | #include <stdint.h> | |
| 19 | #include <unwind.h> | |
| 20 | ||
| 21 | // Unable to unwind in the ARM index table (section 5 EHABI). | |
| 22 | #define UNW_EXIDX_CANTUNWIND 0x1 | |
| 23 | ||
| 24 | static inline uint32_t signExtendPrel31(uint32_t data) { | |
| 25 | return data | ((data & 0x40000000u) << 1); | |
| 26 | } | |
| 27 | ||
| 28 | static inline uint32_t readPrel31(const uint32_t *data) { | |
| 29 | return (((uint32_t)(uintptr_t)data) + signExtendPrel31(*data)); | |
| 30 | } | |
| 31 | ||
| 32 | #if defined(__cplusplus) | |
| 33 | extern "C" { | |
| 34 | #endif | |
| 35 | ||
| 36 | extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr0( | |
| 37 | _Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context); | |
| 38 | ||
| 39 | extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr1( | |
| 40 | _Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context); | |
| 41 | ||
| 42 | extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr2( | |
| 43 | _Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context); | |
| 44 | ||
| 45 | #if defined(__cplusplus) | |
| 46 | } // extern "C" | |
| 47 | #endif | |
| 48 | ||
| 49 | #endif // defined(_LIBUNWIND_ARM_EHABI) | |
| 50 | ||
| 51 | #endif // __UNWIND_EHABI_H__ |
libunwind/src/Unwind-seh.cpp created+491| ... | ... | @@ -0,0 +1,491 @@ |
| 1 | //===--------------------------- Unwind-seh.cpp ---------------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is dual licensed under the MIT and the University of Illinois Open | |
| 6 | // Source Licenses. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | //===----------------------------------------------------------------------===// | |
| 9 | // | |
| 10 | // Implements SEH-based Itanium C++ exceptions. | |
| 11 | // | |
| 12 | //===----------------------------------------------------------------------===// | |
| 13 | ||
| 14 | #include "config.h" | |
| 15 | ||
| 16 | #if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) | |
| 17 | ||
| 18 | #include <unwind.h> | |
| 19 | ||
| 20 | #include <stdint.h> | |
| 21 | #include <stdbool.h> | |
| 22 | #include <stdlib.h> | |
| 23 | ||
| 24 | #include <windef.h> | |
| 25 | #include <excpt.h> | |
| 26 | #include <winnt.h> | |
| 27 | #include <ntstatus.h> | |
| 28 | ||
| 29 | #include "libunwind_ext.h" | |
| 30 | #include "UnwindCursor.hpp" | |
| 31 | ||
| 32 | using namespace libunwind; | |
| 33 | ||
| 34 | #define STATUS_USER_DEFINED (1u << 29) | |
| 35 | ||
| 36 | #define STATUS_GCC_MAGIC (('G' << 16) | ('C' << 8) | 'C') | |
| 37 | ||
| 38 | #define MAKE_CUSTOM_STATUS(s, c) \ | |
| 39 | ((NTSTATUS)(((s) << 30) | STATUS_USER_DEFINED | (c))) | |
| 40 | #define MAKE_GCC_EXCEPTION(c) \ | |
| 41 | MAKE_CUSTOM_STATUS(STATUS_SEVERITY_SUCCESS, STATUS_GCC_MAGIC | ((c) << 24)) | |
| 42 | ||
| 43 | /// SEH exception raised by libunwind when the program calls | |
| 44 | /// \c _Unwind_RaiseException. | |
| 45 | #define STATUS_GCC_THROW MAKE_GCC_EXCEPTION(0) // 0x20474343 | |
| 46 | /// SEH exception raised by libunwind to initiate phase 2 of exception | |
| 47 | /// handling. | |
| 48 | #define STATUS_GCC_UNWIND MAKE_GCC_EXCEPTION(1) // 0x21474343 | |
| 49 | ||
| 50 | /// Class of foreign exceptions based on unrecognized SEH exceptions. | |
| 51 | static const uint64_t kSEHExceptionClass = 0x434C4E4753454800; // CLNGSEH\0 | |
| 52 | ||
| 53 | /// Exception cleanup routine used by \c _GCC_specific_handler to | |
| 54 | /// free foreign exceptions. | |
| 55 | static void seh_exc_cleanup(_Unwind_Reason_Code urc, _Unwind_Exception *exc) { | |
| 56 | if (exc->exception_class != kSEHExceptionClass) | |
| 57 | _LIBUNWIND_ABORT("SEH cleanup called on non-SEH exception"); | |
| 58 | free(exc); | |
| 59 | } | |
| 60 | ||
| 61 | static int _unw_init_seh(unw_cursor_t *cursor, CONTEXT *ctx); | |
| 62 | static DISPATCHER_CONTEXT *_unw_seh_get_disp_ctx(unw_cursor_t *cursor); | |
| 63 | static void _unw_seh_set_disp_ctx(unw_cursor_t *cursor, DISPATCHER_CONTEXT *disp); | |
| 64 | ||
| 65 | /// Common implementation of SEH-style handler functions used by Itanium- | |
| 66 | /// style frames. Depending on how and why it was called, it may do one of: | |
| 67 | /// a) Delegate to the given Itanium-style personality function; or | |
| 68 | /// b) Initiate a collided unwind to halt unwinding. | |
| 69 | _LIBUNWIND_EXPORT EXCEPTION_DISPOSITION | |
| 70 | _GCC_specific_handler(PEXCEPTION_RECORD ms_exc, PVOID frame, PCONTEXT ms_ctx, | |
| 71 | DISPATCHER_CONTEXT *disp, __personality_routine pers) { | |
| 72 | unw_context_t uc; | |
| 73 | unw_cursor_t cursor; | |
| 74 | _Unwind_Exception *exc; | |
| 75 | _Unwind_Action action; | |
| 76 | struct _Unwind_Context *ctx = nullptr; | |
| 77 | _Unwind_Reason_Code urc; | |
| 78 | uintptr_t retval, target; | |
| 79 | bool ours = false; | |
| 80 | ||
| 81 | _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler(%#010x(%x), %p)", ms_exc->ExceptionCode, ms_exc->ExceptionFlags, frame); | |
| 82 | if (ms_exc->ExceptionCode == STATUS_GCC_UNWIND) { | |
| 83 | if (IS_TARGET_UNWIND(ms_exc->ExceptionFlags)) { | |
| 84 | // Set up the upper return value (the lower one and the target PC | |
| 85 | // were set in the call to RtlUnwindEx()) for the landing pad. | |
| 86 | #ifdef __x86_64__ | |
| 87 | disp->ContextRecord->Rdx = ms_exc->ExceptionInformation[3]; | |
| 88 | #elif defined(__arm__) | |
| 89 | disp->ContextRecord->R1 = ms_exc->ExceptionInformation[3]; | |
| 90 | #elif defined(__aarch64__) | |
| 91 | disp->ContextRecord->X1 = ms_exc->ExceptionInformation[3]; | |
| 92 | #endif | |
| 93 | } | |
| 94 | // This is the collided unwind to the landing pad. Nothing to do. | |
| 95 | return ExceptionContinueSearch; | |
| 96 | } | |
| 97 | ||
| 98 | if (ms_exc->ExceptionCode == STATUS_GCC_THROW) { | |
| 99 | // This is (probably) a libunwind-controlled exception/unwind. Recover the | |
| 100 | // parameters which we set below, and pass them to the personality function. | |
| 101 | ours = true; | |
| 102 | exc = (_Unwind_Exception *)ms_exc->ExceptionInformation[0]; | |
| 103 | if (!IS_UNWINDING(ms_exc->ExceptionFlags) && ms_exc->NumberParameters > 1) { | |
| 104 | ctx = (struct _Unwind_Context *)ms_exc->ExceptionInformation[1]; | |
| 105 | action = (_Unwind_Action)ms_exc->ExceptionInformation[2]; | |
| 106 | } | |
| 107 | } else { | |
| 108 | // Foreign exception. | |
| 109 | exc = (_Unwind_Exception *)malloc(sizeof(_Unwind_Exception)); | |
| 110 | exc->exception_class = kSEHExceptionClass; | |
| 111 | exc->exception_cleanup = seh_exc_cleanup; | |
| 112 | memset(exc->private_, 0, sizeof(exc->private_)); | |
| 113 | } | |
| 114 | if (!ctx) { | |
| 115 | _unw_init_seh(&cursor, disp->ContextRecord); | |
| 116 | _unw_seh_set_disp_ctx(&cursor, disp); | |
| 117 | unw_set_reg(&cursor, UNW_REG_IP, disp->ControlPc-1); | |
| 118 | ctx = (struct _Unwind_Context *)&cursor; | |
| 119 | ||
| 120 | if (!IS_UNWINDING(ms_exc->ExceptionFlags)) { | |
| 121 | if (ours && ms_exc->NumberParameters > 1) | |
| 122 | action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_FORCE_UNWIND); | |
| 123 | else | |
| 124 | action = _UA_SEARCH_PHASE; | |
| 125 | } else { | |
| 126 | if (ours && ms_exc->ExceptionInformation[1] == (ULONG_PTR)frame) | |
| 127 | action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME); | |
| 128 | else | |
| 129 | action = _UA_CLEANUP_PHASE; | |
| 130 | } | |
| 131 | } | |
| 132 | ||
| 133 | _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler() calling personality function %p(1, %d, %llx, %p, %p)", pers, action, exc->exception_class, exc, ctx); | |
| 134 | urc = pers(1, action, exc->exception_class, exc, ctx); | |
| 135 | _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler() personality returned %d", urc); | |
| 136 | switch (urc) { | |
| 137 | case _URC_CONTINUE_UNWIND: | |
| 138 | // If we're in phase 2, and the personality routine said to continue | |
| 139 | // at the target frame, we're in real trouble. | |
| 140 | if (action & _UA_HANDLER_FRAME) | |
| 141 | _LIBUNWIND_ABORT("Personality continued unwind at the target frame!"); | |
| 142 | return ExceptionContinueSearch; | |
| 143 | case _URC_HANDLER_FOUND: | |
| 144 | // If we were called by __libunwind_seh_personality(), indicate that | |
| 145 | // a handler was found; otherwise, initiate phase 2 by unwinding. | |
| 146 | if (ours && ms_exc->NumberParameters > 1) | |
| 147 | return 4 /* ExecptionExecuteHandler in mingw */; | |
| 148 | // This should never happen in phase 2. | |
| 149 | if (IS_UNWINDING(ms_exc->ExceptionFlags)) | |
| 150 | _LIBUNWIND_ABORT("Personality indicated exception handler in phase 2!"); | |
| 151 | exc->private_[1] = (ULONG_PTR)frame; | |
| 152 | if (ours) { | |
| 153 | ms_exc->NumberParameters = 4; | |
| 154 | ms_exc->ExceptionInformation[1] = (ULONG_PTR)frame; | |
| 155 | } | |
| 156 | // FIXME: Indicate target frame in foreign case! | |
| 157 | // phase 2: the clean up phase | |
| 158 | RtlUnwindEx(frame, (PVOID)disp->ControlPc, ms_exc, exc, ms_ctx, disp->HistoryTable); | |
| 159 | _LIBUNWIND_ABORT("RtlUnwindEx() failed"); | |
| 160 | case _URC_INSTALL_CONTEXT: { | |
| 161 | // If we were called by __libunwind_seh_personality(), indicate that | |
| 162 | // a handler was found; otherwise, it's time to initiate a collided | |
| 163 | // unwind to the target. | |
| 164 | if (ours && !IS_UNWINDING(ms_exc->ExceptionFlags) && ms_exc->NumberParameters > 1) | |
| 165 | return 4 /* ExecptionExecuteHandler in mingw */; | |
| 166 | // This should never happen in phase 1. | |
| 167 | if (!IS_UNWINDING(ms_exc->ExceptionFlags)) | |
| 168 | _LIBUNWIND_ABORT("Personality installed context during phase 1!"); | |
| 169 | #ifdef __x86_64__ | |
| 170 | exc->private_[2] = disp->TargetIp; | |
| 171 | unw_get_reg(&cursor, UNW_X86_64_RAX, &retval); | |
| 172 | unw_get_reg(&cursor, UNW_X86_64_RDX, &exc->private_[3]); | |
| 173 | #elif defined(__arm__) | |
| 174 | exc->private_[2] = disp->TargetPc; | |
| 175 | unw_get_reg(&cursor, UNW_ARM_R0, &retval); | |
| 176 | unw_get_reg(&cursor, UNW_ARM_R1, &exc->private_[3]); | |
| 177 | #elif defined(__aarch64__) | |
| 178 | exc->private_[2] = disp->TargetPc; | |
| 179 | unw_get_reg(&cursor, UNW_ARM64_X0, &retval); | |
| 180 | unw_get_reg(&cursor, UNW_ARM64_X1, &exc->private_[3]); | |
| 181 | #endif | |
| 182 | unw_get_reg(&cursor, UNW_REG_IP, &target); | |
| 183 | ms_exc->ExceptionCode = STATUS_GCC_UNWIND; | |
| 184 | #ifdef __x86_64__ | |
| 185 | ms_exc->ExceptionInformation[2] = disp->TargetIp; | |
| 186 | #elif defined(__arm__) || defined(__aarch64__) | |
| 187 | ms_exc->ExceptionInformation[2] = disp->TargetPc; | |
| 188 | #endif | |
| 189 | ms_exc->ExceptionInformation[3] = exc->private_[3]; | |
| 190 | // Give NTRTL some scratch space to keep track of the collided unwind. | |
| 191 | // Don't use the one that was passed in; we don't want to overwrite the | |
| 192 | // context in the DISPATCHER_CONTEXT. | |
| 193 | CONTEXT new_ctx; | |
| 194 | RtlUnwindEx(frame, (PVOID)target, ms_exc, (PVOID)retval, &new_ctx, disp->HistoryTable); | |
| 195 | _LIBUNWIND_ABORT("RtlUnwindEx() failed"); | |
| 196 | } | |
| 197 | // Anything else indicates a serious problem. | |
| 198 | default: return ExceptionContinueExecution; | |
| 199 | } | |
| 200 | } | |
| 201 | ||
| 202 | /// Personality function returned by \c unw_get_proc_info() in SEH contexts. | |
| 203 | /// This is a wrapper that calls the real SEH handler function, which in | |
| 204 | /// turn (at least, for Itanium-style frames) calls the real Itanium | |
| 205 | /// personality function (see \c _GCC_specific_handler()). | |
| 206 | extern "C" _Unwind_Reason_Code | |
| 207 | __libunwind_seh_personality(int version, _Unwind_Action state, | |
| 208 | uint64_t klass, _Unwind_Exception *exc, | |
| 209 | struct _Unwind_Context *context) { | |
| 210 | EXCEPTION_RECORD ms_exc; | |
| 211 | bool phase2 = (state & (_UA_SEARCH_PHASE|_UA_CLEANUP_PHASE)) == _UA_CLEANUP_PHASE; | |
| 212 | ms_exc.ExceptionCode = STATUS_GCC_THROW; | |
| 213 | ms_exc.ExceptionFlags = 0; | |
| 214 | ms_exc.NumberParameters = 3; | |
| 215 | ms_exc.ExceptionInformation[0] = (ULONG_PTR)exc; | |
| 216 | ms_exc.ExceptionInformation[1] = (ULONG_PTR)context; | |
| 217 | ms_exc.ExceptionInformation[2] = state; | |
| 218 | DISPATCHER_CONTEXT *disp_ctx = _unw_seh_get_disp_ctx((unw_cursor_t *)context); | |
| 219 | EXCEPTION_DISPOSITION ms_act = disp_ctx->LanguageHandler(&ms_exc, | |
| 220 | (PVOID)disp_ctx->EstablisherFrame, | |
| 221 | disp_ctx->ContextRecord, | |
| 222 | disp_ctx); | |
| 223 | switch (ms_act) { | |
| 224 | case ExceptionContinueSearch: return _URC_CONTINUE_UNWIND; | |
| 225 | case 4 /*ExceptionExecuteHandler*/: | |
| 226 | return phase2 ? _URC_INSTALL_CONTEXT : _URC_HANDLER_FOUND; | |
| 227 | default: | |
| 228 | return phase2 ? _URC_FATAL_PHASE2_ERROR : _URC_FATAL_PHASE1_ERROR; | |
| 229 | } | |
| 230 | } | |
| 231 | ||
| 232 | static _Unwind_Reason_Code | |
| 233 | unwind_phase2_forced(unw_context_t *uc, | |
| 234 | _Unwind_Exception *exception_object, | |
| 235 | _Unwind_Stop_Fn stop, void *stop_parameter) { | |
| 236 | unw_cursor_t cursor2; | |
| 237 | unw_init_local(&cursor2, uc); | |
| 238 | ||
| 239 | // Walk each frame until we reach where search phase said to stop | |
| 240 | while (unw_step(&cursor2) > 0) { | |
| 241 | ||
| 242 | // Update info about this frame. | |
| 243 | unw_proc_info_t frameInfo; | |
| 244 | if (unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) { | |
| 245 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): unw_step " | |
| 246 | "failed => _URC_END_OF_STACK", | |
| 247 | (void *)exception_object); | |
| 248 | return _URC_FATAL_PHASE2_ERROR; | |
| 249 | } | |
| 250 | ||
| 251 | // When tracing, print state information. | |
| 252 | if (_LIBUNWIND_TRACING_UNWINDING) { | |
| 253 | char functionBuf[512]; | |
| 254 | const char *functionName = functionBuf; | |
| 255 | unw_word_t offset; | |
| 256 | if ((unw_get_proc_name(&cursor2, functionBuf, sizeof(functionBuf), | |
| 257 | &offset) != UNW_ESUCCESS) || | |
| 258 | (frameInfo.start_ip + offset > frameInfo.end_ip)) | |
| 259 | functionName = ".anonymous."; | |
| 260 | _LIBUNWIND_TRACE_UNWINDING( | |
| 261 | "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIx64 | |
| 262 | ", func=%s, lsda=0x%" PRIx64 ", personality=0x%" PRIx64, | |
| 263 | (void *)exception_object, frameInfo.start_ip, functionName, | |
| 264 | frameInfo.lsda, frameInfo.handler); | |
| 265 | } | |
| 266 | ||
| 267 | // Call stop function at each frame. | |
| 268 | _Unwind_Action action = | |
| 269 | (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE); | |
| 270 | _Unwind_Reason_Code stopResult = | |
| 271 | (*stop)(1, action, exception_object->exception_class, exception_object, | |
| 272 | (struct _Unwind_Context *)(&cursor2), stop_parameter); | |
| 273 | _LIBUNWIND_TRACE_UNWINDING( | |
| 274 | "unwind_phase2_forced(ex_ojb=%p): stop function returned %d", | |
| 275 | (void *)exception_object, stopResult); | |
| 276 | if (stopResult != _URC_NO_REASON) { | |
| 277 | _LIBUNWIND_TRACE_UNWINDING( | |
| 278 | "unwind_phase2_forced(ex_ojb=%p): stopped by stop function", | |
| 279 | (void *)exception_object); | |
| 280 | return _URC_FATAL_PHASE2_ERROR; | |
| 281 | } | |
| 282 | ||
| 283 | // If there is a personality routine, tell it we are unwinding. | |
| 284 | if (frameInfo.handler != 0) { | |
| 285 | __personality_routine p = | |
| 286 | (__personality_routine)(intptr_t)(frameInfo.handler); | |
| 287 | _LIBUNWIND_TRACE_UNWINDING( | |
| 288 | "unwind_phase2_forced(ex_ojb=%p): calling personality function %p", | |
| 289 | (void *)exception_object, (void *)(uintptr_t)p); | |
| 290 | _Unwind_Reason_Code personalityResult = | |
| 291 | (*p)(1, action, exception_object->exception_class, exception_object, | |
| 292 | (struct _Unwind_Context *)(&cursor2)); | |
| 293 | switch (personalityResult) { | |
| 294 | case _URC_CONTINUE_UNWIND: | |
| 295 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " | |
| 296 | "personality returned " | |
| 297 | "_URC_CONTINUE_UNWIND", | |
| 298 | (void *)exception_object); | |
| 299 | // Destructors called, continue unwinding | |
| 300 | break; | |
| 301 | case _URC_INSTALL_CONTEXT: | |
| 302 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " | |
| 303 | "personality returned " | |
| 304 | "_URC_INSTALL_CONTEXT", | |
| 305 | (void *)exception_object); | |
| 306 | // We may get control back if landing pad calls _Unwind_Resume(). | |
| 307 | unw_resume(&cursor2); | |
| 308 | break; | |
| 309 | default: | |
| 310 | // Personality routine returned an unknown result code. | |
| 311 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " | |
| 312 | "personality returned %d, " | |
| 313 | "_URC_FATAL_PHASE2_ERROR", | |
| 314 | (void *)exception_object, personalityResult); | |
| 315 | return _URC_FATAL_PHASE2_ERROR; | |
| 316 | } | |
| 317 | } | |
| 318 | } | |
| 319 | ||
| 320 | // Call stop function one last time and tell it we've reached the end | |
| 321 | // of the stack. | |
| 322 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop " | |
| 323 | "function with _UA_END_OF_STACK", | |
| 324 | (void *)exception_object); | |
| 325 | _Unwind_Action lastAction = | |
| 326 | (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK); | |
| 327 | (*stop)(1, lastAction, exception_object->exception_class, exception_object, | |
| 328 | (struct _Unwind_Context *)(&cursor2), stop_parameter); | |
| 329 | ||
| 330 | // Clean up phase did not resume at the frame that the search phase said it | |
| 331 | // would. | |
| 332 | return _URC_FATAL_PHASE2_ERROR; | |
| 333 | } | |
| 334 | ||
| 335 | /// Called by \c __cxa_throw(). Only returns if there is a fatal error. | |
| 336 | _LIBUNWIND_EXPORT _Unwind_Reason_Code | |
| 337 | _Unwind_RaiseException(_Unwind_Exception *exception_object) { | |
| 338 | _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)", | |
| 339 | (void *)exception_object); | |
| 340 | ||
| 341 | // Mark that this is a non-forced unwind, so _Unwind_Resume() | |
| 342 | // can do the right thing. | |
| 343 | memset(exception_object->private_, 0, sizeof(exception_object->private_)); | |
| 344 | ||
| 345 | // phase 1: the search phase | |
| 346 | // We'll let the system do that for us. | |
| 347 | RaiseException(STATUS_GCC_THROW, 0, 1, (ULONG_PTR *)&exception_object); | |
| 348 | ||
| 349 | // If we get here, either something went horribly wrong or we reached the | |
| 350 | // top of the stack. Either way, let libc++abi call std::terminate(). | |
| 351 | return _URC_END_OF_STACK; | |
| 352 | } | |
| 353 | ||
| 354 | /// When \c _Unwind_RaiseException() is in phase2, it hands control | |
| 355 | /// to the personality function at each frame. The personality | |
| 356 | /// may force a jump to a landing pad in that function; the landing | |
| 357 | /// pad code may then call \c _Unwind_Resume() to continue with the | |
| 358 | /// unwinding. Note: the call to \c _Unwind_Resume() is from compiler | |
| 359 | /// geneated user code. All other \c _Unwind_* routines are called | |
| 360 | /// by the C++ runtime \c __cxa_* routines. | |
| 361 | /// | |
| 362 | /// Note: re-throwing an exception (as opposed to continuing the unwind) | |
| 363 | /// is implemented by having the code call \c __cxa_rethrow() which | |
| 364 | /// in turn calls \c _Unwind_Resume_or_Rethrow(). | |
| 365 | _LIBUNWIND_EXPORT void | |
| 366 | _Unwind_Resume(_Unwind_Exception *exception_object) { | |
| 367 | _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)", (void *)exception_object); | |
| 368 | ||
| 369 | if (exception_object->private_[0] != 0) { | |
| 370 | unw_context_t uc; | |
| 371 | ||
| 372 | unw_getcontext(&uc); | |
| 373 | unwind_phase2_forced(&uc, exception_object, | |
| 374 | (_Unwind_Stop_Fn) exception_object->private_[0], | |
| 375 | (void *)exception_object->private_[4]); | |
| 376 | } else { | |
| 377 | // Recover the parameters for the unwind from the exception object | |
| 378 | // so we can start unwinding again. | |
| 379 | EXCEPTION_RECORD ms_exc; | |
| 380 | CONTEXT ms_ctx; | |
| 381 | UNWIND_HISTORY_TABLE hist; | |
| 382 | ||
| 383 | memset(&ms_exc, 0, sizeof(ms_exc)); | |
| 384 | memset(&hist, 0, sizeof(hist)); | |
| 385 | ms_exc.ExceptionCode = STATUS_GCC_THROW; | |
| 386 | ms_exc.ExceptionFlags = EXCEPTION_NONCONTINUABLE; | |
| 387 | ms_exc.NumberParameters = 4; | |
| 388 | ms_exc.ExceptionInformation[0] = (ULONG_PTR)exception_object; | |
| 389 | ms_exc.ExceptionInformation[1] = exception_object->private_[1]; | |
| 390 | ms_exc.ExceptionInformation[2] = exception_object->private_[2]; | |
| 391 | ms_exc.ExceptionInformation[3] = exception_object->private_[3]; | |
| 392 | RtlUnwindEx((PVOID)exception_object->private_[1], | |
| 393 | (PVOID)exception_object->private_[2], &ms_exc, | |
| 394 | exception_object, &ms_ctx, &hist); | |
| 395 | } | |
| 396 | ||
| 397 | // Clients assume _Unwind_Resume() does not return, so all we can do is abort. | |
| 398 | _LIBUNWIND_ABORT("_Unwind_Resume() can't return"); | |
| 399 | } | |
| 400 | ||
| 401 | /// Not used by C++. | |
| 402 | /// Unwinds stack, calling "stop" function at each frame. | |
| 403 | /// Could be used to implement \c longjmp(). | |
| 404 | _LIBUNWIND_EXPORT _Unwind_Reason_Code | |
| 405 | _Unwind_ForcedUnwind(_Unwind_Exception *exception_object, | |
| 406 | _Unwind_Stop_Fn stop, void *stop_parameter) { | |
| 407 | _LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)", | |
| 408 | (void *)exception_object, (void *)(uintptr_t)stop); | |
| 409 | unw_context_t uc; | |
| 410 | unw_getcontext(&uc); | |
| 411 | ||
| 412 | // Mark that this is a forced unwind, so _Unwind_Resume() can do | |
| 413 | // the right thing. | |
| 414 | exception_object->private_[0] = (uintptr_t) stop; | |
| 415 | exception_object->private_[4] = (uintptr_t) stop_parameter; | |
| 416 | ||
| 417 | // do it | |
| 418 | return unwind_phase2_forced(&uc, exception_object, stop, stop_parameter); | |
| 419 | } | |
| 420 | ||
| 421 | /// Called by personality handler during phase 2 to get LSDA for current frame. | |
| 422 | _LIBUNWIND_EXPORT uintptr_t | |
| 423 | _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { | |
| 424 | uintptr_t result = (uintptr_t)_unw_seh_get_disp_ctx((unw_cursor_t *)context)->HandlerData; | |
| 425 | _LIBUNWIND_TRACE_API( | |
| 426 | "_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR, | |
| 427 | (void *)context, result); | |
| 428 | return result; | |
| 429 | } | |
| 430 | ||
| 431 | /// Called by personality handler during phase 2 to find the start of the | |
| 432 | /// function. | |
| 433 | _LIBUNWIND_EXPORT uintptr_t | |
| 434 | _Unwind_GetRegionStart(struct _Unwind_Context *context) { | |
| 435 | DISPATCHER_CONTEXT *disp = _unw_seh_get_disp_ctx((unw_cursor_t *)context); | |
| 436 | uintptr_t result = (uintptr_t)disp->FunctionEntry->BeginAddress + disp->ImageBase; | |
| 437 | _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%" PRIxPTR, | |
| 438 | (void *)context, result); | |
| 439 | return result; | |
| 440 | } | |
| 441 | ||
| 442 | static int | |
| 443 | _unw_init_seh(unw_cursor_t *cursor, CONTEXT *context) { | |
| 444 | #ifdef _LIBUNWIND_TARGET_X86_64 | |
| 445 | new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_x86_64>( | |
| 446 | context, LocalAddressSpace::sThisAddressSpace); | |
| 447 | auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor); | |
| 448 | co->setInfoBasedOnIPRegister(); | |
| 449 | return UNW_ESUCCESS; | |
| 450 | #elif defined(_LIBUNWIND_TARGET_ARM) | |
| 451 | new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_arm>( | |
| 452 | context, LocalAddressSpace::sThisAddressSpace); | |
| 453 | auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor); | |
| 454 | co->setInfoBasedOnIPRegister(); | |
| 455 | return UNW_ESUCCESS; | |
| 456 | #elif defined(_LIBUNWIND_TARGET_AARCH64) | |
| 457 | new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_arm64>( | |
| 458 | context, LocalAddressSpace::sThisAddressSpace); | |
| 459 | auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor); | |
| 460 | co->setInfoBasedOnIPRegister(); | |
| 461 | return UNW_ESUCCESS; | |
| 462 | #else | |
| 463 | return UNW_EINVAL; | |
| 464 | #endif | |
| 465 | } | |
| 466 | ||
| 467 | static DISPATCHER_CONTEXT * | |
| 468 | _unw_seh_get_disp_ctx(unw_cursor_t *cursor) { | |
| 469 | #ifdef _LIBUNWIND_TARGET_X86_64 | |
| 470 | return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_x86_64> *>(cursor)->getDispatcherContext(); | |
| 471 | #elif defined(_LIBUNWIND_TARGET_ARM) | |
| 472 | return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm> *>(cursor)->getDispatcherContext(); | |
| 473 | #elif defined(_LIBUNWIND_TARGET_AARCH64) | |
| 474 | return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm64> *>(cursor)->getDispatcherContext(); | |
| 475 | #else | |
| 476 | return nullptr; | |
| 477 | #endif | |
| 478 | } | |
| 479 | ||
| 480 | static void | |
| 481 | _unw_seh_set_disp_ctx(unw_cursor_t *cursor, DISPATCHER_CONTEXT *disp) { | |
| 482 | #ifdef _LIBUNWIND_TARGET_X86_64 | |
| 483 | reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_x86_64> *>(cursor)->setDispatcherContext(disp); | |
| 484 | #elif defined(_LIBUNWIND_TARGET_ARM) | |
| 485 | reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm> *>(cursor)->setDispatcherContext(disp); | |
| 486 | #elif defined(_LIBUNWIND_TARGET_AARCH64) | |
| 487 | reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm64> *>(cursor)->setDispatcherContext(disp); | |
| 488 | #endif | |
| 489 | } | |
| 490 | ||
| 491 | #endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) |
libunwind/src/Unwind-sjlj.c created+504| ... | ... | @@ -0,0 +1,504 @@ |
| 1 | //===--------------------------- Unwind-sjlj.c ----------------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is dual licensed under the MIT and the University of Illinois Open | |
| 6 | // Source Licenses. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | // | |
| 9 | // Implements setjump-longjump based C++ exceptions | |
| 10 | // | |
| 11 | //===----------------------------------------------------------------------===// | |
| 12 | ||
| 13 | #include <unwind.h> | |
| 14 | ||
| 15 | #include <stdint.h> | |
| 16 | #include <stdbool.h> | |
| 17 | #include <stdlib.h> | |
| 18 | ||
| 19 | #include "config.h" | |
| 20 | ||
| 21 | /// With SJLJ based exceptions, any function that has a catch clause or needs to | |
| 22 | /// do any clean up when an exception propagates through it, needs to call | |
| 23 | /// \c _Unwind_SjLj_Register at the start of the function and | |
| 24 | /// \c _Unwind_SjLj_Unregister at the end. The register function is called with | |
| 25 | /// the address of a block of memory in the function's stack frame. The runtime | |
| 26 | /// keeps a linked list (stack) of these blocks - one per thread. The calling | |
| 27 | /// function also sets the personality and lsda fields of the block. | |
| 28 | ||
| 29 | #if defined(_LIBUNWIND_BUILD_SJLJ_APIS) | |
| 30 | ||
| 31 | struct _Unwind_FunctionContext { | |
| 32 | // next function in stack of handlers | |
| 33 | struct _Unwind_FunctionContext *prev; | |
| 34 | ||
| 35 | // set by calling function before registering to be the landing pad | |
| 36 | uint32_t resumeLocation; | |
| 37 | ||
| 38 | // set by personality handler to be parameters passed to landing pad function | |
| 39 | uint32_t resumeParameters[4]; | |
| 40 | ||
| 41 | // set by calling function before registering | |
| 42 | __personality_routine personality; // arm offset=24 | |
| 43 | uintptr_t lsda; // arm offset=28 | |
| 44 | ||
| 45 | // variable length array, contains registers to restore | |
| 46 | // 0 = r7, 1 = pc, 2 = sp | |
| 47 | void *jbuf[]; | |
| 48 | }; | |
| 49 | ||
| 50 | #if defined(_LIBUNWIND_HAS_NO_THREADS) | |
| 51 | # define _LIBUNWIND_THREAD_LOCAL | |
| 52 | #else | |
| 53 | # if __STDC_VERSION__ >= 201112L | |
| 54 | # define _LIBUNWIND_THREAD_LOCAL _Thread_local | |
| 55 | # elif defined(_WIN32) | |
| 56 | # define _LIBUNWIND_THREAD_LOCAL __declspec(thread) | |
| 57 | # elif defined(__GNUC__) || defined(__clang__) | |
| 58 | # define _LIBUNWIND_THREAD_LOCAL __thread | |
| 59 | # else | |
| 60 | # error Unable to create thread local storage | |
| 61 | # endif | |
| 62 | #endif | |
| 63 | ||
| 64 | ||
| 65 | #if !defined(FOR_DYLD) | |
| 66 | ||
| 67 | #if defined(__APPLE__) | |
| 68 | #include <System/pthread_machdep.h> | |
| 69 | #else | |
| 70 | static _LIBUNWIND_THREAD_LOCAL struct _Unwind_FunctionContext *stack = NULL; | |
| 71 | #endif | |
| 72 | ||
| 73 | static struct _Unwind_FunctionContext *__Unwind_SjLj_GetTopOfFunctionStack() { | |
| 74 | #if defined(__APPLE__) | |
| 75 | return _pthread_getspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key); | |
| 76 | #else | |
| 77 | return stack; | |
| 78 | #endif | |
| 79 | } | |
| 80 | ||
| 81 | static void | |
| 82 | __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext *fc) { | |
| 83 | #if defined(__APPLE__) | |
| 84 | _pthread_setspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key, fc); | |
| 85 | #else | |
| 86 | stack = fc; | |
| 87 | #endif | |
| 88 | } | |
| 89 | ||
| 90 | #endif | |
| 91 | ||
| 92 | ||
| 93 | /// Called at start of each function that catches exceptions | |
| 94 | _LIBUNWIND_EXPORT void | |
| 95 | _Unwind_SjLj_Register(struct _Unwind_FunctionContext *fc) { | |
| 96 | fc->prev = __Unwind_SjLj_GetTopOfFunctionStack(); | |
| 97 | __Unwind_SjLj_SetTopOfFunctionStack(fc); | |
| 98 | } | |
| 99 | ||
| 100 | ||
| 101 | /// Called at end of each function that catches exceptions | |
| 102 | _LIBUNWIND_EXPORT void | |
| 103 | _Unwind_SjLj_Unregister(struct _Unwind_FunctionContext *fc) { | |
| 104 | __Unwind_SjLj_SetTopOfFunctionStack(fc->prev); | |
| 105 | } | |
| 106 | ||
| 107 | ||
| 108 | static _Unwind_Reason_Code | |
| 109 | unwind_phase1(struct _Unwind_Exception *exception_object) { | |
| 110 | _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack(); | |
| 111 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase1: initial function-context=%p", c); | |
| 112 | ||
| 113 | // walk each frame looking for a place to stop | |
| 114 | for (bool handlerNotFound = true; handlerNotFound; c = c->prev) { | |
| 115 | ||
| 116 | // check for no more frames | |
| 117 | if (c == NULL) { | |
| 118 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): reached " | |
| 119 | "bottom => _URC_END_OF_STACK", | |
| 120 | exception_object); | |
| 121 | return _URC_END_OF_STACK; | |
| 122 | } | |
| 123 | ||
| 124 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase1: function-context=%p", c); | |
| 125 | // if there is a personality routine, ask it if it will want to stop at this | |
| 126 | // frame | |
| 127 | if (c->personality != NULL) { | |
| 128 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): calling " | |
| 129 | "personality function %p", | |
| 130 | exception_object, c->personality); | |
| 131 | _Unwind_Reason_Code personalityResult = (*c->personality)( | |
| 132 | 1, _UA_SEARCH_PHASE, exception_object->exception_class, | |
| 133 | exception_object, (struct _Unwind_Context *)c); | |
| 134 | switch (personalityResult) { | |
| 135 | case _URC_HANDLER_FOUND: | |
| 136 | // found a catch clause or locals that need destructing in this frame | |
| 137 | // stop search and remember function context | |
| 138 | handlerNotFound = false; | |
| 139 | exception_object->private_2 = (uintptr_t) c; | |
| 140 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): " | |
| 141 | "_URC_HANDLER_FOUND", exception_object); | |
| 142 | return _URC_NO_REASON; | |
| 143 | ||
| 144 | case _URC_CONTINUE_UNWIND: | |
| 145 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): " | |
| 146 | "_URC_CONTINUE_UNWIND", exception_object); | |
| 147 | // continue unwinding | |
| 148 | break; | |
| 149 | ||
| 150 | default: | |
| 151 | // something went wrong | |
| 152 | _LIBUNWIND_TRACE_UNWINDING( | |
| 153 | "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR", | |
| 154 | exception_object); | |
| 155 | return _URC_FATAL_PHASE1_ERROR; | |
| 156 | } | |
| 157 | } | |
| 158 | } | |
| 159 | return _URC_NO_REASON; | |
| 160 | } | |
| 161 | ||
| 162 | ||
| 163 | static _Unwind_Reason_Code | |
| 164 | unwind_phase2(struct _Unwind_Exception *exception_object) { | |
| 165 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)", exception_object); | |
| 166 | ||
| 167 | // walk each frame until we reach where search phase said to stop | |
| 168 | _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack(); | |
| 169 | while (true) { | |
| 170 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2s(ex_ojb=%p): context=%p", | |
| 171 | exception_object, c); | |
| 172 | ||
| 173 | // check for no more frames | |
| 174 | if (c == NULL) { | |
| 175 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached " | |
| 176 | "bottom => _URC_END_OF_STACK", | |
| 177 | exception_object); | |
| 178 | return _URC_END_OF_STACK; | |
| 179 | } | |
| 180 | ||
| 181 | // if there is a personality routine, tell it we are unwinding | |
| 182 | if (c->personality != NULL) { | |
| 183 | _Unwind_Action action = _UA_CLEANUP_PHASE; | |
| 184 | if ((uintptr_t) c == exception_object->private_2) | |
| 185 | action = (_Unwind_Action)( | |
| 186 | _UA_CLEANUP_PHASE | | |
| 187 | _UA_HANDLER_FRAME); // tell personality this was the frame it marked | |
| 188 | // in phase 1 | |
| 189 | _Unwind_Reason_Code personalityResult = | |
| 190 | (*c->personality)(1, action, exception_object->exception_class, | |
| 191 | exception_object, (struct _Unwind_Context *)c); | |
| 192 | switch (personalityResult) { | |
| 193 | case _URC_CONTINUE_UNWIND: | |
| 194 | // continue unwinding | |
| 195 | _LIBUNWIND_TRACE_UNWINDING( | |
| 196 | "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND", | |
| 197 | exception_object); | |
| 198 | if ((uintptr_t) c == exception_object->private_2) { | |
| 199 | // phase 1 said we would stop at this frame, but we did not... | |
| 200 | _LIBUNWIND_ABORT("during phase1 personality function said it would " | |
| 201 | "stop here, but now if phase2 it did not stop here"); | |
| 202 | } | |
| 203 | break; | |
| 204 | case _URC_INSTALL_CONTEXT: | |
| 205 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): " | |
| 206 | "_URC_INSTALL_CONTEXT, will resume at " | |
| 207 | "landing pad %p", | |
| 208 | exception_object, c->jbuf[1]); | |
| 209 | // personality routine says to transfer control to landing pad | |
| 210 | // we may get control back if landing pad calls _Unwind_Resume() | |
| 211 | __Unwind_SjLj_SetTopOfFunctionStack(c); | |
| 212 | __builtin_longjmp(c->jbuf, 1); | |
| 213 | // unw_resume() only returns if there was an error | |
| 214 | return _URC_FATAL_PHASE2_ERROR; | |
| 215 | default: | |
| 216 | // something went wrong | |
| 217 | _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d", | |
| 218 | personalityResult); | |
| 219 | return _URC_FATAL_PHASE2_ERROR; | |
| 220 | } | |
| 221 | } | |
| 222 | c = c->prev; | |
| 223 | } | |
| 224 | ||
| 225 | // clean up phase did not resume at the frame that the search phase said it | |
| 226 | // would | |
| 227 | return _URC_FATAL_PHASE2_ERROR; | |
| 228 | } | |
| 229 | ||
| 230 | ||
| 231 | static _Unwind_Reason_Code | |
| 232 | unwind_phase2_forced(struct _Unwind_Exception *exception_object, | |
| 233 | _Unwind_Stop_Fn stop, void *stop_parameter) { | |
| 234 | // walk each frame until we reach where search phase said to stop | |
| 235 | _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack(); | |
| 236 | while (true) { | |
| 237 | ||
| 238 | // get next frame (skip over first which is _Unwind_RaiseException) | |
| 239 | if (c == NULL) { | |
| 240 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached " | |
| 241 | "bottom => _URC_END_OF_STACK", | |
| 242 | exception_object); | |
| 243 | return _URC_END_OF_STACK; | |
| 244 | } | |
| 245 | ||
| 246 | // call stop function at each frame | |
| 247 | _Unwind_Action action = | |
| 248 | (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE); | |
| 249 | _Unwind_Reason_Code stopResult = | |
| 250 | (*stop)(1, action, exception_object->exception_class, exception_object, | |
| 251 | (struct _Unwind_Context *)c, stop_parameter); | |
| 252 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " | |
| 253 | "stop function returned %d", | |
| 254 | exception_object, stopResult); | |
| 255 | if (stopResult != _URC_NO_REASON) { | |
| 256 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " | |
| 257 | "stopped by stop function", | |
| 258 | exception_object); | |
| 259 | return _URC_FATAL_PHASE2_ERROR; | |
| 260 | } | |
| 261 | ||
| 262 | // if there is a personality routine, tell it we are unwinding | |
| 263 | if (c->personality != NULL) { | |
| 264 | __personality_routine p = (__personality_routine) c->personality; | |
| 265 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " | |
| 266 | "calling personality function %p", | |
| 267 | exception_object, p); | |
| 268 | _Unwind_Reason_Code personalityResult = | |
| 269 | (*p)(1, action, exception_object->exception_class, exception_object, | |
| 270 | (struct _Unwind_Context *)c); | |
| 271 | switch (personalityResult) { | |
| 272 | case _URC_CONTINUE_UNWIND: | |
| 273 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " | |
| 274 | "personality returned _URC_CONTINUE_UNWIND", | |
| 275 | exception_object); | |
| 276 | // destructors called, continue unwinding | |
| 277 | break; | |
| 278 | case _URC_INSTALL_CONTEXT: | |
| 279 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " | |
| 280 | "personality returned _URC_INSTALL_CONTEXT", | |
| 281 | exception_object); | |
| 282 | // we may get control back if landing pad calls _Unwind_Resume() | |
| 283 | __Unwind_SjLj_SetTopOfFunctionStack(c); | |
| 284 | __builtin_longjmp(c->jbuf, 1); | |
| 285 | break; | |
| 286 | default: | |
| 287 | // something went wrong | |
| 288 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " | |
| 289 | "personality returned %d, " | |
| 290 | "_URC_FATAL_PHASE2_ERROR", | |
| 291 | exception_object, personalityResult); | |
| 292 | return _URC_FATAL_PHASE2_ERROR; | |
| 293 | } | |
| 294 | } | |
| 295 | c = c->prev; | |
| 296 | } | |
| 297 | ||
| 298 | // call stop function one last time and tell it we've reached the end of the | |
| 299 | // stack | |
| 300 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop " | |
| 301 | "function with _UA_END_OF_STACK", | |
| 302 | exception_object); | |
| 303 | _Unwind_Action lastAction = | |
| 304 | (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK); | |
| 305 | (*stop)(1, lastAction, exception_object->exception_class, exception_object, | |
| 306 | (struct _Unwind_Context *)c, stop_parameter); | |
| 307 | ||
| 308 | // clean up phase did not resume at the frame that the search phase said it | |
| 309 | // would | |
| 310 | return _URC_FATAL_PHASE2_ERROR; | |
| 311 | } | |
| 312 | ||
| 313 | ||
| 314 | /// Called by __cxa_throw. Only returns if there is a fatal error | |
| 315 | _LIBUNWIND_EXPORT _Unwind_Reason_Code | |
| 316 | _Unwind_SjLj_RaiseException(struct _Unwind_Exception *exception_object) { | |
| 317 | _LIBUNWIND_TRACE_API("_Unwind_SjLj_RaiseException(ex_obj=%p)", exception_object); | |
| 318 | ||
| 319 | // mark that this is a non-forced unwind, so _Unwind_Resume() can do the right | |
| 320 | // thing | |
| 321 | exception_object->private_1 = 0; | |
| 322 | exception_object->private_2 = 0; | |
| 323 | ||
| 324 | // phase 1: the search phase | |
| 325 | _Unwind_Reason_Code phase1 = unwind_phase1(exception_object); | |
| 326 | if (phase1 != _URC_NO_REASON) | |
| 327 | return phase1; | |
| 328 | ||
| 329 | // phase 2: the clean up phase | |
| 330 | return unwind_phase2(exception_object); | |
| 331 | } | |
| 332 | ||
| 333 | ||
| 334 | ||
| 335 | /// When _Unwind_RaiseException() is in phase2, it hands control | |
| 336 | /// to the personality function at each frame. The personality | |
| 337 | /// may force a jump to a landing pad in that function, the landing | |
| 338 | /// pad code may then call _Unwind_Resume() to continue with the | |
| 339 | /// unwinding. Note: the call to _Unwind_Resume() is from compiler | |
| 340 | /// geneated user code. All other _Unwind_* routines are called | |
| 341 | /// by the C++ runtime __cxa_* routines. | |
| 342 | /// | |
| 343 | /// Re-throwing an exception is implemented by having the code call | |
| 344 | /// __cxa_rethrow() which in turn calls _Unwind_Resume_or_Rethrow() | |
| 345 | _LIBUNWIND_EXPORT void | |
| 346 | _Unwind_SjLj_Resume(struct _Unwind_Exception *exception_object) { | |
| 347 | _LIBUNWIND_TRACE_API("_Unwind_SjLj_Resume(ex_obj=%p)", exception_object); | |
| 348 | ||
| 349 | if (exception_object->private_1 != 0) | |
| 350 | unwind_phase2_forced(exception_object, | |
| 351 | (_Unwind_Stop_Fn) exception_object->private_1, | |
| 352 | (void *)exception_object->private_2); | |
| 353 | else | |
| 354 | unwind_phase2(exception_object); | |
| 355 | ||
| 356 | // clients assume _Unwind_Resume() does not return, so all we can do is abort. | |
| 357 | _LIBUNWIND_ABORT("_Unwind_SjLj_Resume() can't return"); | |
| 358 | } | |
| 359 | ||
| 360 | ||
| 361 | /// Called by __cxa_rethrow(). | |
| 362 | _LIBUNWIND_EXPORT _Unwind_Reason_Code | |
| 363 | _Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception *exception_object) { | |
| 364 | _LIBUNWIND_TRACE_API("__Unwind_SjLj_Resume_or_Rethrow(ex_obj=%p), " | |
| 365 | "private_1=%ld", | |
| 366 | exception_object, exception_object->private_1); | |
| 367 | // If this is non-forced and a stopping place was found, then this is a | |
| 368 | // re-throw. | |
| 369 | // Call _Unwind_RaiseException() as if this was a new exception. | |
| 370 | if (exception_object->private_1 == 0) { | |
| 371 | return _Unwind_SjLj_RaiseException(exception_object); | |
| 372 | // should return if there is no catch clause, so that __cxa_rethrow can call | |
| 373 | // std::terminate() | |
| 374 | } | |
| 375 | ||
| 376 | // Call through to _Unwind_Resume() which distiguishes between forced and | |
| 377 | // regular exceptions. | |
| 378 | _Unwind_SjLj_Resume(exception_object); | |
| 379 | _LIBUNWIND_ABORT("__Unwind_SjLj_Resume_or_Rethrow() called " | |
| 380 | "_Unwind_SjLj_Resume() which unexpectedly returned"); | |
| 381 | } | |
| 382 | ||
| 383 | ||
| 384 | /// Called by personality handler during phase 2 to get LSDA for current frame. | |
| 385 | _LIBUNWIND_EXPORT uintptr_t | |
| 386 | _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { | |
| 387 | _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; | |
| 388 | _LIBUNWIND_TRACE_API("_Unwind_GetLanguageSpecificData(context=%p) " | |
| 389 | "=> 0x%0lX", context, ufc->lsda); | |
| 390 | return ufc->lsda; | |
| 391 | } | |
| 392 | ||
| 393 | ||
| 394 | /// Called by personality handler during phase 2 to get register values. | |
| 395 | _LIBUNWIND_EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, | |
| 396 | int index) { | |
| 397 | _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d)", | |
| 398 | context, index); | |
| 399 | _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; | |
| 400 | return ufc->resumeParameters[index]; | |
| 401 | } | |
| 402 | ||
| 403 | ||
| 404 | /// Called by personality handler during phase 2 to alter register values. | |
| 405 | _LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index, | |
| 406 | uintptr_t new_value) { | |
| 407 | _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0lX)" | |
| 408 | , context, index, new_value); | |
| 409 | _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; | |
| 410 | ufc->resumeParameters[index] = new_value; | |
| 411 | } | |
| 412 | ||
| 413 | ||
| 414 | /// Called by personality handler during phase 2 to get instruction pointer. | |
| 415 | _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) { | |
| 416 | _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; | |
| 417 | _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%lX", context, | |
| 418 | ufc->resumeLocation + 1); | |
| 419 | return ufc->resumeLocation + 1; | |
| 420 | } | |
| 421 | ||
| 422 | ||
| 423 | /// Called by personality handler during phase 2 to get instruction pointer. | |
| 424 | /// ipBefore is a boolean that says if IP is already adjusted to be the call | |
| 425 | /// site address. Normally IP is the return address. | |
| 426 | _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context, | |
| 427 | int *ipBefore) { | |
| 428 | _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; | |
| 429 | *ipBefore = 0; | |
| 430 | _LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p, %p) => 0x%lX", | |
| 431 | context, ipBefore, ufc->resumeLocation + 1); | |
| 432 | return ufc->resumeLocation + 1; | |
| 433 | } | |
| 434 | ||
| 435 | ||
| 436 | /// Called by personality handler during phase 2 to alter instruction pointer. | |
| 437 | _LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context, | |
| 438 | uintptr_t new_value) { | |
| 439 | _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0lX)", | |
| 440 | context, new_value); | |
| 441 | _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; | |
| 442 | ufc->resumeLocation = new_value - 1; | |
| 443 | } | |
| 444 | ||
| 445 | ||
| 446 | /// Called by personality handler during phase 2 to find the start of the | |
| 447 | /// function. | |
| 448 | _LIBUNWIND_EXPORT uintptr_t | |
| 449 | _Unwind_GetRegionStart(struct _Unwind_Context *context) { | |
| 450 | // Not supported or needed for sjlj based unwinding | |
| 451 | (void)context; | |
| 452 | _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p)", context); | |
| 453 | return 0; | |
| 454 | } | |
| 455 | ||
| 456 | ||
| 457 | /// Called by personality handler during phase 2 if a foreign exception | |
| 458 | /// is caught. | |
| 459 | _LIBUNWIND_EXPORT void | |
| 460 | _Unwind_DeleteException(struct _Unwind_Exception *exception_object) { | |
| 461 | _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)", | |
| 462 | exception_object); | |
| 463 | if (exception_object->exception_cleanup != NULL) | |
| 464 | (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, | |
| 465 | exception_object); | |
| 466 | } | |
| 467 | ||
| 468 | ||
| 469 | ||
| 470 | /// Called by personality handler during phase 2 to get base address for data | |
| 471 | /// relative encodings. | |
| 472 | _LIBUNWIND_EXPORT uintptr_t | |
| 473 | _Unwind_GetDataRelBase(struct _Unwind_Context *context) { | |
| 474 | // Not supported or needed for sjlj based unwinding | |
| 475 | (void)context; | |
| 476 | _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", context); | |
| 477 | _LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented"); | |
| 478 | } | |
| 479 | ||
| 480 | ||
| 481 | /// Called by personality handler during phase 2 to get base address for text | |
| 482 | /// relative encodings. | |
| 483 | _LIBUNWIND_EXPORT uintptr_t | |
| 484 | _Unwind_GetTextRelBase(struct _Unwind_Context *context) { | |
| 485 | // Not supported or needed for sjlj based unwinding | |
| 486 | (void)context; | |
| 487 | _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)", context); | |
| 488 | _LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented"); | |
| 489 | } | |
| 490 | ||
| 491 | ||
| 492 | /// Called by personality handler to get "Call Frame Area" for current frame. | |
| 493 | _LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) { | |
| 494 | _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p)", context); | |
| 495 | if (context != NULL) { | |
| 496 | _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; | |
| 497 | // Setjmp/longjmp based exceptions don't have a true CFA. | |
| 498 | // Instead, the SP in the jmpbuf is the closest approximation. | |
| 499 | return (uintptr_t) ufc->jbuf[2]; | |
| 500 | } | |
| 501 | return 0; | |
| 502 | } | |
| 503 | ||
| 504 | #endif // defined(_LIBUNWIND_BUILD_SJLJ_APIS) |
libunwind/src/UnwindCursor.hpp created+1975| ... | ... | @@ -0,0 +1,1975 @@ |
| 1 | //===------------------------- UnwindCursor.hpp ---------------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is dual licensed under the MIT and the University of Illinois Open | |
| 6 | // Source Licenses. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | // | |
| 9 | // C++ interface to lower levels of libunwind | |
| 10 | //===----------------------------------------------------------------------===// | |
| 11 | ||
| 12 | #ifndef __UNWINDCURSOR_HPP__ | |
| 13 | #define __UNWINDCURSOR_HPP__ | |
| 14 | ||
| 15 | #include <algorithm> | |
| 16 | #include <stdint.h> | |
| 17 | #include <stdio.h> | |
| 18 | #include <stdlib.h> | |
| 19 | #include <unwind.h> | |
| 20 | ||
| 21 | #ifdef _WIN32 | |
| 22 | #include <windows.h> | |
| 23 | #include <ntverp.h> | |
| 24 | #endif | |
| 25 | #ifdef __APPLE__ | |
| 26 | #include <mach-o/dyld.h> | |
| 27 | #endif | |
| 28 | ||
| 29 | #if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) | |
| 30 | // Provide a definition for the DISPATCHER_CONTEXT struct for old (Win7 and | |
| 31 | // earlier) SDKs. | |
| 32 | // MinGW-w64 has always provided this struct. | |
| 33 | #if defined(_WIN32) && defined(_LIBUNWIND_TARGET_X86_64) && \ | |
| 34 | !defined(__MINGW32__) && VER_PRODUCTBUILD < 8000 | |
| 35 | struct _DISPATCHER_CONTEXT { | |
| 36 | ULONG64 ControlPc; | |
| 37 | ULONG64 ImageBase; | |
| 38 | PRUNTIME_FUNCTION FunctionEntry; | |
| 39 | ULONG64 EstablisherFrame; | |
| 40 | ULONG64 TargetIp; | |
| 41 | PCONTEXT ContextRecord; | |
| 42 | PEXCEPTION_ROUTINE LanguageHandler; | |
| 43 | PVOID HandlerData; | |
| 44 | PUNWIND_HISTORY_TABLE HistoryTable; | |
| 45 | ULONG ScopeIndex; | |
| 46 | ULONG Fill0; | |
| 47 | }; | |
| 48 | #endif | |
| 49 | ||
| 50 | struct UNWIND_INFO { | |
| 51 | uint8_t Version : 3; | |
| 52 | uint8_t Flags : 5; | |
| 53 | uint8_t SizeOfProlog; | |
| 54 | uint8_t CountOfCodes; | |
| 55 | uint8_t FrameRegister : 4; | |
| 56 | uint8_t FrameOffset : 4; | |
| 57 | uint16_t UnwindCodes[2]; | |
| 58 | }; | |
| 59 | ||
| 60 | extern "C" _Unwind_Reason_Code __libunwind_seh_personality( | |
| 61 | int, _Unwind_Action, uint64_t, _Unwind_Exception *, | |
| 62 | struct _Unwind_Context *); | |
| 63 | ||
| 64 | #endif | |
| 65 | ||
| 66 | #include "config.h" | |
| 67 | ||
| 68 | #include "AddressSpace.hpp" | |
| 69 | #include "CompactUnwinder.hpp" | |
| 70 | #include "config.h" | |
| 71 | #include "DwarfInstructions.hpp" | |
| 72 | #include "EHHeaderParser.hpp" | |
| 73 | #include "libunwind.h" | |
| 74 | #include "Registers.hpp" | |
| 75 | #include "RWMutex.hpp" | |
| 76 | #include "Unwind-EHABI.h" | |
| 77 | ||
| 78 | namespace libunwind { | |
| 79 | ||
| 80 | #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) | |
| 81 | /// Cache of recently found FDEs. | |
| 82 | template <typename A> | |
| 83 | class _LIBUNWIND_HIDDEN DwarfFDECache { | |
| 84 | typedef typename A::pint_t pint_t; | |
| 85 | public: | |
| 86 | static pint_t findFDE(pint_t mh, pint_t pc); | |
| 87 | static void add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde); | |
| 88 | static void removeAllIn(pint_t mh); | |
| 89 | static void iterateCacheEntries(void (*func)(unw_word_t ip_start, | |
| 90 | unw_word_t ip_end, | |
| 91 | unw_word_t fde, unw_word_t mh)); | |
| 92 | ||
| 93 | private: | |
| 94 | ||
| 95 | struct entry { | |
| 96 | pint_t mh; | |
| 97 | pint_t ip_start; | |
| 98 | pint_t ip_end; | |
| 99 | pint_t fde; | |
| 100 | }; | |
| 101 | ||
| 102 | // These fields are all static to avoid needing an initializer. | |
| 103 | // There is only one instance of this class per process. | |
| 104 | static RWMutex _lock; | |
| 105 | #ifdef __APPLE__ | |
| 106 | static void dyldUnloadHook(const struct mach_header *mh, intptr_t slide); | |
| 107 | static bool _registeredForDyldUnloads; | |
| 108 | #endif | |
| 109 | // Can't use std::vector<> here because this code is below libc++. | |
| 110 | static entry *_buffer; | |
| 111 | static entry *_bufferUsed; | |
| 112 | static entry *_bufferEnd; | |
| 113 | static entry _initialBuffer[64]; | |
| 114 | }; | |
| 115 | ||
| 116 | template <typename A> | |
| 117 | typename DwarfFDECache<A>::entry * | |
| 118 | DwarfFDECache<A>::_buffer = _initialBuffer; | |
| 119 | ||
| 120 | template <typename A> | |
| 121 | typename DwarfFDECache<A>::entry * | |
| 122 | DwarfFDECache<A>::_bufferUsed = _initialBuffer; | |
| 123 | ||
| 124 | template <typename A> | |
| 125 | typename DwarfFDECache<A>::entry * | |
| 126 | DwarfFDECache<A>::_bufferEnd = &_initialBuffer[64]; | |
| 127 | ||
| 128 | template <typename A> | |
| 129 | typename DwarfFDECache<A>::entry DwarfFDECache<A>::_initialBuffer[64]; | |
| 130 | ||
| 131 | template <typename A> | |
| 132 | RWMutex DwarfFDECache<A>::_lock; | |
| 133 | ||
| 134 | #ifdef __APPLE__ | |
| 135 | template <typename A> | |
| 136 | bool DwarfFDECache<A>::_registeredForDyldUnloads = false; | |
| 137 | #endif | |
| 138 | ||
| 139 | template <typename A> | |
| 140 | typename A::pint_t DwarfFDECache<A>::findFDE(pint_t mh, pint_t pc) { | |
| 141 | pint_t result = 0; | |
| 142 | _LIBUNWIND_LOG_IF_FALSE(_lock.lock_shared()); | |
| 143 | for (entry *p = _buffer; p < _bufferUsed; ++p) { | |
| 144 | if ((mh == p->mh) || (mh == 0)) { | |
| 145 | if ((p->ip_start <= pc) && (pc < p->ip_end)) { | |
| 146 | result = p->fde; | |
| 147 | break; | |
| 148 | } | |
| 149 | } | |
| 150 | } | |
| 151 | _LIBUNWIND_LOG_IF_FALSE(_lock.unlock_shared()); | |
| 152 | return result; | |
| 153 | } | |
| 154 | ||
| 155 | template <typename A> | |
| 156 | void DwarfFDECache<A>::add(pint_t mh, pint_t ip_start, pint_t ip_end, | |
| 157 | pint_t fde) { | |
| 158 | #if !defined(_LIBUNWIND_NO_HEAP) | |
| 159 | _LIBUNWIND_LOG_IF_FALSE(_lock.lock()); | |
| 160 | if (_bufferUsed >= _bufferEnd) { | |
| 161 | size_t oldSize = (size_t)(_bufferEnd - _buffer); | |
| 162 | size_t newSize = oldSize * 4; | |
| 163 | // Can't use operator new (we are below it). | |
| 164 | entry *newBuffer = (entry *)malloc(newSize * sizeof(entry)); | |
| 165 | memcpy(newBuffer, _buffer, oldSize * sizeof(entry)); | |
| 166 | if (_buffer != _initialBuffer) | |
| 167 | free(_buffer); | |
| 168 | _buffer = newBuffer; | |
| 169 | _bufferUsed = &newBuffer[oldSize]; | |
| 170 | _bufferEnd = &newBuffer[newSize]; | |
| 171 | } | |
| 172 | _bufferUsed->mh = mh; | |
| 173 | _bufferUsed->ip_start = ip_start; | |
| 174 | _bufferUsed->ip_end = ip_end; | |
| 175 | _bufferUsed->fde = fde; | |
| 176 | ++_bufferUsed; | |
| 177 | #ifdef __APPLE__ | |
| 178 | if (!_registeredForDyldUnloads) { | |
| 179 | _dyld_register_func_for_remove_image(&dyldUnloadHook); | |
| 180 | _registeredForDyldUnloads = true; | |
| 181 | } | |
| 182 | #endif | |
| 183 | _LIBUNWIND_LOG_IF_FALSE(_lock.unlock()); | |
| 184 | #endif | |
| 185 | } | |
| 186 | ||
| 187 | template <typename A> | |
| 188 | void DwarfFDECache<A>::removeAllIn(pint_t mh) { | |
| 189 | _LIBUNWIND_LOG_IF_FALSE(_lock.lock()); | |
| 190 | entry *d = _buffer; | |
| 191 | for (const entry *s = _buffer; s < _bufferUsed; ++s) { | |
| 192 | if (s->mh != mh) { | |
| 193 | if (d != s) | |
| 194 | *d = *s; | |
| 195 | ++d; | |
| 196 | } | |
| 197 | } | |
| 198 | _bufferUsed = d; | |
| 199 | _LIBUNWIND_LOG_IF_FALSE(_lock.unlock()); | |
| 200 | } | |
| 201 | ||
| 202 | #ifdef __APPLE__ | |
| 203 | template <typename A> | |
| 204 | void DwarfFDECache<A>::dyldUnloadHook(const struct mach_header *mh, intptr_t ) { | |
| 205 | removeAllIn((pint_t) mh); | |
| 206 | } | |
| 207 | #endif | |
| 208 | ||
| 209 | template <typename A> | |
| 210 | void DwarfFDECache<A>::iterateCacheEntries(void (*func)( | |
| 211 | unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) { | |
| 212 | _LIBUNWIND_LOG_IF_FALSE(_lock.lock()); | |
| 213 | for (entry *p = _buffer; p < _bufferUsed; ++p) { | |
| 214 | (*func)(p->ip_start, p->ip_end, p->fde, p->mh); | |
| 215 | } | |
| 216 | _LIBUNWIND_LOG_IF_FALSE(_lock.unlock()); | |
| 217 | } | |
| 218 | #endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) | |
| 219 | ||
| 220 | ||
| 221 | #define arrayoffsetof(type, index, field) ((size_t)(&((type *)0)[index].field)) | |
| 222 | ||
| 223 | #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) | |
| 224 | template <typename A> class UnwindSectionHeader { | |
| 225 | public: | |
| 226 | UnwindSectionHeader(A &addressSpace, typename A::pint_t addr) | |
| 227 | : _addressSpace(addressSpace), _addr(addr) {} | |
| 228 | ||
| 229 | uint32_t version() const { | |
| 230 | return _addressSpace.get32(_addr + | |
| 231 | offsetof(unwind_info_section_header, version)); | |
| 232 | } | |
| 233 | uint32_t commonEncodingsArraySectionOffset() const { | |
| 234 | return _addressSpace.get32(_addr + | |
| 235 | offsetof(unwind_info_section_header, | |
| 236 | commonEncodingsArraySectionOffset)); | |
| 237 | } | |
| 238 | uint32_t commonEncodingsArrayCount() const { | |
| 239 | return _addressSpace.get32(_addr + offsetof(unwind_info_section_header, | |
| 240 | commonEncodingsArrayCount)); | |
| 241 | } | |
| 242 | uint32_t personalityArraySectionOffset() const { | |
| 243 | return _addressSpace.get32(_addr + offsetof(unwind_info_section_header, | |
| 244 | personalityArraySectionOffset)); | |
| 245 | } | |
| 246 | uint32_t personalityArrayCount() const { | |
| 247 | return _addressSpace.get32( | |
| 248 | _addr + offsetof(unwind_info_section_header, personalityArrayCount)); | |
| 249 | } | |
| 250 | uint32_t indexSectionOffset() const { | |
| 251 | return _addressSpace.get32( | |
| 252 | _addr + offsetof(unwind_info_section_header, indexSectionOffset)); | |
| 253 | } | |
| 254 | uint32_t indexCount() const { | |
| 255 | return _addressSpace.get32( | |
| 256 | _addr + offsetof(unwind_info_section_header, indexCount)); | |
| 257 | } | |
| 258 | ||
| 259 | private: | |
| 260 | A &_addressSpace; | |
| 261 | typename A::pint_t _addr; | |
| 262 | }; | |
| 263 | ||
| 264 | template <typename A> class UnwindSectionIndexArray { | |
| 265 | public: | |
| 266 | UnwindSectionIndexArray(A &addressSpace, typename A::pint_t addr) | |
| 267 | : _addressSpace(addressSpace), _addr(addr) {} | |
| 268 | ||
| 269 | uint32_t functionOffset(uint32_t index) const { | |
| 270 | return _addressSpace.get32( | |
| 271 | _addr + arrayoffsetof(unwind_info_section_header_index_entry, index, | |
| 272 | functionOffset)); | |
| 273 | } | |
| 274 | uint32_t secondLevelPagesSectionOffset(uint32_t index) const { | |
| 275 | return _addressSpace.get32( | |
| 276 | _addr + arrayoffsetof(unwind_info_section_header_index_entry, index, | |
| 277 | secondLevelPagesSectionOffset)); | |
| 278 | } | |
| 279 | uint32_t lsdaIndexArraySectionOffset(uint32_t index) const { | |
| 280 | return _addressSpace.get32( | |
| 281 | _addr + arrayoffsetof(unwind_info_section_header_index_entry, index, | |
| 282 | lsdaIndexArraySectionOffset)); | |
| 283 | } | |
| 284 | ||
| 285 | private: | |
| 286 | A &_addressSpace; | |
| 287 | typename A::pint_t _addr; | |
| 288 | }; | |
| 289 | ||
| 290 | template <typename A> class UnwindSectionRegularPageHeader { | |
| 291 | public: | |
| 292 | UnwindSectionRegularPageHeader(A &addressSpace, typename A::pint_t addr) | |
| 293 | : _addressSpace(addressSpace), _addr(addr) {} | |
| 294 | ||
| 295 | uint32_t kind() const { | |
| 296 | return _addressSpace.get32( | |
| 297 | _addr + offsetof(unwind_info_regular_second_level_page_header, kind)); | |
| 298 | } | |
| 299 | uint16_t entryPageOffset() const { | |
| 300 | return _addressSpace.get16( | |
| 301 | _addr + offsetof(unwind_info_regular_second_level_page_header, | |
| 302 | entryPageOffset)); | |
| 303 | } | |
| 304 | uint16_t entryCount() const { | |
| 305 | return _addressSpace.get16( | |
| 306 | _addr + | |
| 307 | offsetof(unwind_info_regular_second_level_page_header, entryCount)); | |
| 308 | } | |
| 309 | ||
| 310 | private: | |
| 311 | A &_addressSpace; | |
| 312 | typename A::pint_t _addr; | |
| 313 | }; | |
| 314 | ||
| 315 | template <typename A> class UnwindSectionRegularArray { | |
| 316 | public: | |
| 317 | UnwindSectionRegularArray(A &addressSpace, typename A::pint_t addr) | |
| 318 | : _addressSpace(addressSpace), _addr(addr) {} | |
| 319 | ||
| 320 | uint32_t functionOffset(uint32_t index) const { | |
| 321 | return _addressSpace.get32( | |
| 322 | _addr + arrayoffsetof(unwind_info_regular_second_level_entry, index, | |
| 323 | functionOffset)); | |
| 324 | } | |
| 325 | uint32_t encoding(uint32_t index) const { | |
| 326 | return _addressSpace.get32( | |
| 327 | _addr + | |
| 328 | arrayoffsetof(unwind_info_regular_second_level_entry, index, encoding)); | |
| 329 | } | |
| 330 | ||
| 331 | private: | |
| 332 | A &_addressSpace; | |
| 333 | typename A::pint_t _addr; | |
| 334 | }; | |
| 335 | ||
| 336 | template <typename A> class UnwindSectionCompressedPageHeader { | |
| 337 | public: | |
| 338 | UnwindSectionCompressedPageHeader(A &addressSpace, typename A::pint_t addr) | |
| 339 | : _addressSpace(addressSpace), _addr(addr) {} | |
| 340 | ||
| 341 | uint32_t kind() const { | |
| 342 | return _addressSpace.get32( | |
| 343 | _addr + | |
| 344 | offsetof(unwind_info_compressed_second_level_page_header, kind)); | |
| 345 | } | |
| 346 | uint16_t entryPageOffset() const { | |
| 347 | return _addressSpace.get16( | |
| 348 | _addr + offsetof(unwind_info_compressed_second_level_page_header, | |
| 349 | entryPageOffset)); | |
| 350 | } | |
| 351 | uint16_t entryCount() const { | |
| 352 | return _addressSpace.get16( | |
| 353 | _addr + | |
| 354 | offsetof(unwind_info_compressed_second_level_page_header, entryCount)); | |
| 355 | } | |
| 356 | uint16_t encodingsPageOffset() const { | |
| 357 | return _addressSpace.get16( | |
| 358 | _addr + offsetof(unwind_info_compressed_second_level_page_header, | |
| 359 | encodingsPageOffset)); | |
| 360 | } | |
| 361 | uint16_t encodingsCount() const { | |
| 362 | return _addressSpace.get16( | |
| 363 | _addr + offsetof(unwind_info_compressed_second_level_page_header, | |
| 364 | encodingsCount)); | |
| 365 | } | |
| 366 | ||
| 367 | private: | |
| 368 | A &_addressSpace; | |
| 369 | typename A::pint_t _addr; | |
| 370 | }; | |
| 371 | ||
| 372 | template <typename A> class UnwindSectionCompressedArray { | |
| 373 | public: | |
| 374 | UnwindSectionCompressedArray(A &addressSpace, typename A::pint_t addr) | |
| 375 | : _addressSpace(addressSpace), _addr(addr) {} | |
| 376 | ||
| 377 | uint32_t functionOffset(uint32_t index) const { | |
| 378 | return UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET( | |
| 379 | _addressSpace.get32(_addr + index * sizeof(uint32_t))); | |
| 380 | } | |
| 381 | uint16_t encodingIndex(uint32_t index) const { | |
| 382 | return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX( | |
| 383 | _addressSpace.get32(_addr + index * sizeof(uint32_t))); | |
| 384 | } | |
| 385 | ||
| 386 | private: | |
| 387 | A &_addressSpace; | |
| 388 | typename A::pint_t _addr; | |
| 389 | }; | |
| 390 | ||
| 391 | template <typename A> class UnwindSectionLsdaArray { | |
| 392 | public: | |
| 393 | UnwindSectionLsdaArray(A &addressSpace, typename A::pint_t addr) | |
| 394 | : _addressSpace(addressSpace), _addr(addr) {} | |
| 395 | ||
| 396 | uint32_t functionOffset(uint32_t index) const { | |
| 397 | return _addressSpace.get32( | |
| 398 | _addr + arrayoffsetof(unwind_info_section_header_lsda_index_entry, | |
| 399 | index, functionOffset)); | |
| 400 | } | |
| 401 | uint32_t lsdaOffset(uint32_t index) const { | |
| 402 | return _addressSpace.get32( | |
| 403 | _addr + arrayoffsetof(unwind_info_section_header_lsda_index_entry, | |
| 404 | index, lsdaOffset)); | |
| 405 | } | |
| 406 | ||
| 407 | private: | |
| 408 | A &_addressSpace; | |
| 409 | typename A::pint_t _addr; | |
| 410 | }; | |
| 411 | #endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) | |
| 412 | ||
| 413 | class _LIBUNWIND_HIDDEN AbstractUnwindCursor { | |
| 414 | public: | |
| 415 | // NOTE: provide a class specific placement deallocation function (S5.3.4 p20) | |
| 416 | // This avoids an unnecessary dependency to libc++abi. | |
| 417 | void operator delete(void *, size_t) {} | |
| 418 | ||
| 419 | virtual ~AbstractUnwindCursor() {} | |
| 420 | virtual bool validReg(int) { _LIBUNWIND_ABORT("validReg not implemented"); } | |
| 421 | virtual unw_word_t getReg(int) { _LIBUNWIND_ABORT("getReg not implemented"); } | |
| 422 | virtual void setReg(int, unw_word_t) { | |
| 423 | _LIBUNWIND_ABORT("setReg not implemented"); | |
| 424 | } | |
| 425 | virtual bool validFloatReg(int) { | |
| 426 | _LIBUNWIND_ABORT("validFloatReg not implemented"); | |
| 427 | } | |
| 428 | virtual unw_fpreg_t getFloatReg(int) { | |
| 429 | _LIBUNWIND_ABORT("getFloatReg not implemented"); | |
| 430 | } | |
| 431 | virtual void setFloatReg(int, unw_fpreg_t) { | |
| 432 | _LIBUNWIND_ABORT("setFloatReg not implemented"); | |
| 433 | } | |
| 434 | virtual int step() { _LIBUNWIND_ABORT("step not implemented"); } | |
| 435 | virtual void getInfo(unw_proc_info_t *) { | |
| 436 | _LIBUNWIND_ABORT("getInfo not implemented"); | |
| 437 | } | |
| 438 | virtual void jumpto() { _LIBUNWIND_ABORT("jumpto not implemented"); } | |
| 439 | virtual bool isSignalFrame() { | |
| 440 | _LIBUNWIND_ABORT("isSignalFrame not implemented"); | |
| 441 | } | |
| 442 | virtual bool getFunctionName(char *, size_t, unw_word_t *) { | |
| 443 | _LIBUNWIND_ABORT("getFunctionName not implemented"); | |
| 444 | } | |
| 445 | virtual void setInfoBasedOnIPRegister(bool = false) { | |
| 446 | _LIBUNWIND_ABORT("setInfoBasedOnIPRegister not implemented"); | |
| 447 | } | |
| 448 | virtual const char *getRegisterName(int) { | |
| 449 | _LIBUNWIND_ABORT("getRegisterName not implemented"); | |
| 450 | } | |
| 451 | #ifdef __arm__ | |
| 452 | virtual void saveVFPAsX() { _LIBUNWIND_ABORT("saveVFPAsX not implemented"); } | |
| 453 | #endif | |
| 454 | }; | |
| 455 | ||
| 456 | #if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32) | |
| 457 | ||
| 458 | /// \c UnwindCursor contains all state (including all register values) during | |
| 459 | /// an unwind. This is normally stack-allocated inside a unw_cursor_t. | |
| 460 | template <typename A, typename R> | |
| 461 | class UnwindCursor : public AbstractUnwindCursor { | |
| 462 | typedef typename A::pint_t pint_t; | |
| 463 | public: | |
| 464 | UnwindCursor(unw_context_t *context, A &as); | |
| 465 | UnwindCursor(CONTEXT *context, A &as); | |
| 466 | UnwindCursor(A &as, void *threadArg); | |
| 467 | virtual ~UnwindCursor() {} | |
| 468 | virtual bool validReg(int); | |
| 469 | virtual unw_word_t getReg(int); | |
| 470 | virtual void setReg(int, unw_word_t); | |
| 471 | virtual bool validFloatReg(int); | |
| 472 | virtual unw_fpreg_t getFloatReg(int); | |
| 473 | virtual void setFloatReg(int, unw_fpreg_t); | |
| 474 | virtual int step(); | |
| 475 | virtual void getInfo(unw_proc_info_t *); | |
| 476 | virtual void jumpto(); | |
| 477 | virtual bool isSignalFrame(); | |
| 478 | virtual bool getFunctionName(char *buf, size_t len, unw_word_t *off); | |
| 479 | virtual void setInfoBasedOnIPRegister(bool isReturnAddress = false); | |
| 480 | virtual const char *getRegisterName(int num); | |
| 481 | #ifdef __arm__ | |
| 482 | virtual void saveVFPAsX(); | |
| 483 | #endif | |
| 484 | ||
| 485 | DISPATCHER_CONTEXT *getDispatcherContext() { return &_dispContext; } | |
| 486 | void setDispatcherContext(DISPATCHER_CONTEXT *disp) { _dispContext = *disp; } | |
| 487 | ||
| 488 | private: | |
| 489 | ||
| 490 | pint_t getLastPC() const { return _dispContext.ControlPc; } | |
| 491 | void setLastPC(pint_t pc) { _dispContext.ControlPc = pc; } | |
| 492 | RUNTIME_FUNCTION *lookUpSEHUnwindInfo(pint_t pc, pint_t *base) { | |
| 493 | _dispContext.FunctionEntry = RtlLookupFunctionEntry(pc, | |
| 494 | &_dispContext.ImageBase, | |
| 495 | _dispContext.HistoryTable); | |
| 496 | *base = _dispContext.ImageBase; | |
| 497 | return _dispContext.FunctionEntry; | |
| 498 | } | |
| 499 | bool getInfoFromSEH(pint_t pc); | |
| 500 | int stepWithSEHData() { | |
| 501 | _dispContext.LanguageHandler = RtlVirtualUnwind(UNW_FLAG_UHANDLER, | |
| 502 | _dispContext.ImageBase, | |
| 503 | _dispContext.ControlPc, | |
| 504 | _dispContext.FunctionEntry, | |
| 505 | _dispContext.ContextRecord, | |
| 506 | &_dispContext.HandlerData, | |
| 507 | &_dispContext.EstablisherFrame, | |
| 508 | NULL); | |
| 509 | // Update some fields of the unwind info now, since we have them. | |
| 510 | _info.lsda = reinterpret_cast<unw_word_t>(_dispContext.HandlerData); | |
| 511 | if (_dispContext.LanguageHandler) { | |
| 512 | _info.handler = reinterpret_cast<unw_word_t>(__libunwind_seh_personality); | |
| 513 | } else | |
| 514 | _info.handler = 0; | |
| 515 | return UNW_STEP_SUCCESS; | |
| 516 | } | |
| 517 | ||
| 518 | A &_addressSpace; | |
| 519 | unw_proc_info_t _info; | |
| 520 | DISPATCHER_CONTEXT _dispContext; | |
| 521 | CONTEXT _msContext; | |
| 522 | UNWIND_HISTORY_TABLE _histTable; | |
| 523 | bool _unwindInfoMissing; | |
| 524 | }; | |
| 525 | ||
| 526 | ||
| 527 | template <typename A, typename R> | |
| 528 | UnwindCursor<A, R>::UnwindCursor(unw_context_t *context, A &as) | |
| 529 | : _addressSpace(as), _unwindInfoMissing(false) { | |
| 530 | static_assert((check_fit<UnwindCursor<A, R>, unw_cursor_t>::does_fit), | |
| 531 | "UnwindCursor<> does not fit in unw_cursor_t"); | |
| 532 | memset(&_info, 0, sizeof(_info)); | |
| 533 | memset(&_histTable, 0, sizeof(_histTable)); | |
| 534 | _dispContext.ContextRecord = &_msContext; | |
| 535 | _dispContext.HistoryTable = &_histTable; | |
| 536 | // Initialize MS context from ours. | |
| 537 | R r(context); | |
| 538 | _msContext.ContextFlags = CONTEXT_CONTROL|CONTEXT_INTEGER|CONTEXT_FLOATING_POINT; | |
| 539 | #if defined(_LIBUNWIND_TARGET_X86_64) | |
| 540 | _msContext.Rax = r.getRegister(UNW_X86_64_RAX); | |
| 541 | _msContext.Rcx = r.getRegister(UNW_X86_64_RCX); | |
| 542 | _msContext.Rdx = r.getRegister(UNW_X86_64_RDX); | |
| 543 | _msContext.Rbx = r.getRegister(UNW_X86_64_RBX); | |
| 544 | _msContext.Rsp = r.getRegister(UNW_X86_64_RSP); | |
| 545 | _msContext.Rbp = r.getRegister(UNW_X86_64_RBP); | |
| 546 | _msContext.Rsi = r.getRegister(UNW_X86_64_RSI); | |
| 547 | _msContext.Rdi = r.getRegister(UNW_X86_64_RDI); | |
| 548 | _msContext.R8 = r.getRegister(UNW_X86_64_R8); | |
| 549 | _msContext.R9 = r.getRegister(UNW_X86_64_R9); | |
| 550 | _msContext.R10 = r.getRegister(UNW_X86_64_R10); | |
| 551 | _msContext.R11 = r.getRegister(UNW_X86_64_R11); | |
| 552 | _msContext.R12 = r.getRegister(UNW_X86_64_R12); | |
| 553 | _msContext.R13 = r.getRegister(UNW_X86_64_R13); | |
| 554 | _msContext.R14 = r.getRegister(UNW_X86_64_R14); | |
| 555 | _msContext.R15 = r.getRegister(UNW_X86_64_R15); | |
| 556 | _msContext.Rip = r.getRegister(UNW_REG_IP); | |
| 557 | union { | |
| 558 | v128 v; | |
| 559 | M128A m; | |
| 560 | } t; | |
| 561 | t.v = r.getVectorRegister(UNW_X86_64_XMM0); | |
| 562 | _msContext.Xmm0 = t.m; | |
| 563 | t.v = r.getVectorRegister(UNW_X86_64_XMM1); | |
| 564 | _msContext.Xmm1 = t.m; | |
| 565 | t.v = r.getVectorRegister(UNW_X86_64_XMM2); | |
| 566 | _msContext.Xmm2 = t.m; | |
| 567 | t.v = r.getVectorRegister(UNW_X86_64_XMM3); | |
| 568 | _msContext.Xmm3 = t.m; | |
| 569 | t.v = r.getVectorRegister(UNW_X86_64_XMM4); | |
| 570 | _msContext.Xmm4 = t.m; | |
| 571 | t.v = r.getVectorRegister(UNW_X86_64_XMM5); | |
| 572 | _msContext.Xmm5 = t.m; | |
| 573 | t.v = r.getVectorRegister(UNW_X86_64_XMM6); | |
| 574 | _msContext.Xmm6 = t.m; | |
| 575 | t.v = r.getVectorRegister(UNW_X86_64_XMM7); | |
| 576 | _msContext.Xmm7 = t.m; | |
| 577 | t.v = r.getVectorRegister(UNW_X86_64_XMM8); | |
| 578 | _msContext.Xmm8 = t.m; | |
| 579 | t.v = r.getVectorRegister(UNW_X86_64_XMM9); | |
| 580 | _msContext.Xmm9 = t.m; | |
| 581 | t.v = r.getVectorRegister(UNW_X86_64_XMM10); | |
| 582 | _msContext.Xmm10 = t.m; | |
| 583 | t.v = r.getVectorRegister(UNW_X86_64_XMM11); | |
| 584 | _msContext.Xmm11 = t.m; | |
| 585 | t.v = r.getVectorRegister(UNW_X86_64_XMM12); | |
| 586 | _msContext.Xmm12 = t.m; | |
| 587 | t.v = r.getVectorRegister(UNW_X86_64_XMM13); | |
| 588 | _msContext.Xmm13 = t.m; | |
| 589 | t.v = r.getVectorRegister(UNW_X86_64_XMM14); | |
| 590 | _msContext.Xmm14 = t.m; | |
| 591 | t.v = r.getVectorRegister(UNW_X86_64_XMM15); | |
| 592 | _msContext.Xmm15 = t.m; | |
| 593 | #elif defined(_LIBUNWIND_TARGET_ARM) | |
| 594 | _msContext.R0 = r.getRegister(UNW_ARM_R0); | |
| 595 | _msContext.R1 = r.getRegister(UNW_ARM_R1); | |
| 596 | _msContext.R2 = r.getRegister(UNW_ARM_R2); | |
| 597 | _msContext.R3 = r.getRegister(UNW_ARM_R3); | |
| 598 | _msContext.R4 = r.getRegister(UNW_ARM_R4); | |
| 599 | _msContext.R5 = r.getRegister(UNW_ARM_R5); | |
| 600 | _msContext.R6 = r.getRegister(UNW_ARM_R6); | |
| 601 | _msContext.R7 = r.getRegister(UNW_ARM_R7); | |
| 602 | _msContext.R8 = r.getRegister(UNW_ARM_R8); | |
| 603 | _msContext.R9 = r.getRegister(UNW_ARM_R9); | |
| 604 | _msContext.R10 = r.getRegister(UNW_ARM_R10); | |
| 605 | _msContext.R11 = r.getRegister(UNW_ARM_R11); | |
| 606 | _msContext.R12 = r.getRegister(UNW_ARM_R12); | |
| 607 | _msContext.Sp = r.getRegister(UNW_ARM_SP); | |
| 608 | _msContext.Lr = r.getRegister(UNW_ARM_LR); | |
| 609 | _msContext.Pc = r.getRegister(UNW_ARM_IP); | |
| 610 | for (int i = UNW_ARM_D0; i <= UNW_ARM_D31; ++i) { | |
| 611 | union { | |
| 612 | uint64_t w; | |
| 613 | double d; | |
| 614 | } d; | |
| 615 | d.d = r.getFloatRegister(i); | |
| 616 | _msContext.D[i - UNW_ARM_D0] = d.w; | |
| 617 | } | |
| 618 | #elif defined(_LIBUNWIND_TARGET_AARCH64) | |
| 619 | for (int i = UNW_ARM64_X0; i <= UNW_ARM64_X30; ++i) | |
| 620 | _msContext.X[i - UNW_ARM64_X0] = r.getRegister(i); | |
| 621 | _msContext.Sp = r.getRegister(UNW_REG_SP); | |
| 622 | _msContext.Pc = r.getRegister(UNW_REG_IP); | |
| 623 | for (int i = UNW_ARM64_D0; i <= UNW_ARM64_D31; ++i) | |
| 624 | _msContext.V[i - UNW_ARM64_D0].D[0] = r.getFloatRegister(i); | |
| 625 | #endif | |
| 626 | } | |
| 627 | ||
| 628 | template <typename A, typename R> | |
| 629 | UnwindCursor<A, R>::UnwindCursor(CONTEXT *context, A &as) | |
| 630 | : _addressSpace(as), _unwindInfoMissing(false) { | |
| 631 | static_assert((check_fit<UnwindCursor<A, R>, unw_cursor_t>::does_fit), | |
| 632 | "UnwindCursor<> does not fit in unw_cursor_t"); | |
| 633 | memset(&_info, 0, sizeof(_info)); | |
| 634 | memset(&_histTable, 0, sizeof(_histTable)); | |
| 635 | _dispContext.ContextRecord = &_msContext; | |
| 636 | _dispContext.HistoryTable = &_histTable; | |
| 637 | _msContext = *context; | |
| 638 | } | |
| 639 | ||
| 640 | ||
| 641 | template <typename A, typename R> | |
| 642 | bool UnwindCursor<A, R>::validReg(int regNum) { | |
| 643 | if (regNum == UNW_REG_IP || regNum == UNW_REG_SP) return true; | |
| 644 | #if defined(_LIBUNWIND_TARGET_X86_64) | |
| 645 | if (regNum >= UNW_X86_64_RAX && regNum <= UNW_X86_64_R15) return true; | |
| 646 | #elif defined(_LIBUNWIND_TARGET_ARM) | |
| 647 | if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R15) return true; | |
| 648 | #elif defined(_LIBUNWIND_TARGET_AARCH64) | |
| 649 | if (regNum >= UNW_ARM64_X0 && regNum <= UNW_ARM64_X30) return true; | |
| 650 | #endif | |
| 651 | return false; | |
| 652 | } | |
| 653 | ||
| 654 | template <typename A, typename R> | |
| 655 | unw_word_t UnwindCursor<A, R>::getReg(int regNum) { | |
| 656 | switch (regNum) { | |
| 657 | #if defined(_LIBUNWIND_TARGET_X86_64) | |
| 658 | case UNW_REG_IP: return _msContext.Rip; | |
| 659 | case UNW_X86_64_RAX: return _msContext.Rax; | |
| 660 | case UNW_X86_64_RDX: return _msContext.Rdx; | |
| 661 | case UNW_X86_64_RCX: return _msContext.Rcx; | |
| 662 | case UNW_X86_64_RBX: return _msContext.Rbx; | |
| 663 | case UNW_REG_SP: | |
| 664 | case UNW_X86_64_RSP: return _msContext.Rsp; | |
| 665 | case UNW_X86_64_RBP: return _msContext.Rbp; | |
| 666 | case UNW_X86_64_RSI: return _msContext.Rsi; | |
| 667 | case UNW_X86_64_RDI: return _msContext.Rdi; | |
| 668 | case UNW_X86_64_R8: return _msContext.R8; | |
| 669 | case UNW_X86_64_R9: return _msContext.R9; | |
| 670 | case UNW_X86_64_R10: return _msContext.R10; | |
| 671 | case UNW_X86_64_R11: return _msContext.R11; | |
| 672 | case UNW_X86_64_R12: return _msContext.R12; | |
| 673 | case UNW_X86_64_R13: return _msContext.R13; | |
| 674 | case UNW_X86_64_R14: return _msContext.R14; | |
| 675 | case UNW_X86_64_R15: return _msContext.R15; | |
| 676 | #elif defined(_LIBUNWIND_TARGET_ARM) | |
| 677 | case UNW_ARM_R0: return _msContext.R0; | |
| 678 | case UNW_ARM_R1: return _msContext.R1; | |
| 679 | case UNW_ARM_R2: return _msContext.R2; | |
| 680 | case UNW_ARM_R3: return _msContext.R3; | |
| 681 | case UNW_ARM_R4: return _msContext.R4; | |
| 682 | case UNW_ARM_R5: return _msContext.R5; | |
| 683 | case UNW_ARM_R6: return _msContext.R6; | |
| 684 | case UNW_ARM_R7: return _msContext.R7; | |
| 685 | case UNW_ARM_R8: return _msContext.R8; | |
| 686 | case UNW_ARM_R9: return _msContext.R9; | |
| 687 | case UNW_ARM_R10: return _msContext.R10; | |
| 688 | case UNW_ARM_R11: return _msContext.R11; | |
| 689 | case UNW_ARM_R12: return _msContext.R12; | |
| 690 | case UNW_REG_SP: | |
| 691 | case UNW_ARM_SP: return _msContext.Sp; | |
| 692 | case UNW_ARM_LR: return _msContext.Lr; | |
| 693 | case UNW_REG_IP: | |
| 694 | case UNW_ARM_IP: return _msContext.Pc; | |
| 695 | #elif defined(_LIBUNWIND_TARGET_AARCH64) | |
| 696 | case UNW_REG_SP: return _msContext.Sp; | |
| 697 | case UNW_REG_IP: return _msContext.Pc; | |
| 698 | default: return _msContext.X[regNum - UNW_ARM64_X0]; | |
| 699 | #endif | |
| 700 | } | |
| 701 | _LIBUNWIND_ABORT("unsupported register"); | |
| 702 | } | |
| 703 | ||
| 704 | template <typename A, typename R> | |
| 705 | void UnwindCursor<A, R>::setReg(int regNum, unw_word_t value) { | |
| 706 | switch (regNum) { | |
| 707 | #if defined(_LIBUNWIND_TARGET_X86_64) | |
| 708 | case UNW_REG_IP: _msContext.Rip = value; break; | |
| 709 | case UNW_X86_64_RAX: _msContext.Rax = value; break; | |
| 710 | case UNW_X86_64_RDX: _msContext.Rdx = value; break; | |
| 711 | case UNW_X86_64_RCX: _msContext.Rcx = value; break; | |
| 712 | case UNW_X86_64_RBX: _msContext.Rbx = value; break; | |
| 713 | case UNW_REG_SP: | |
| 714 | case UNW_X86_64_RSP: _msContext.Rsp = value; break; | |
| 715 | case UNW_X86_64_RBP: _msContext.Rbp = value; break; | |
| 716 | case UNW_X86_64_RSI: _msContext.Rsi = value; break; | |
| 717 | case UNW_X86_64_RDI: _msContext.Rdi = value; break; | |
| 718 | case UNW_X86_64_R8: _msContext.R8 = value; break; | |
| 719 | case UNW_X86_64_R9: _msContext.R9 = value; break; | |
| 720 | case UNW_X86_64_R10: _msContext.R10 = value; break; | |
| 721 | case UNW_X86_64_R11: _msContext.R11 = value; break; | |
| 722 | case UNW_X86_64_R12: _msContext.R12 = value; break; | |
| 723 | case UNW_X86_64_R13: _msContext.R13 = value; break; | |
| 724 | case UNW_X86_64_R14: _msContext.R14 = value; break; | |
| 725 | case UNW_X86_64_R15: _msContext.R15 = value; break; | |
| 726 | #elif defined(_LIBUNWIND_TARGET_ARM) | |
| 727 | case UNW_ARM_R0: _msContext.R0 = value; break; | |
| 728 | case UNW_ARM_R1: _msContext.R1 = value; break; | |
| 729 | case UNW_ARM_R2: _msContext.R2 = value; break; | |
| 730 | case UNW_ARM_R3: _msContext.R3 = value; break; | |
| 731 | case UNW_ARM_R4: _msContext.R4 = value; break; | |
| 732 | case UNW_ARM_R5: _msContext.R5 = value; break; | |
| 733 | case UNW_ARM_R6: _msContext.R6 = value; break; | |
| 734 | case UNW_ARM_R7: _msContext.R7 = value; break; | |
| 735 | case UNW_ARM_R8: _msContext.R8 = value; break; | |
| 736 | case UNW_ARM_R9: _msContext.R9 = value; break; | |
| 737 | case UNW_ARM_R10: _msContext.R10 = value; break; | |
| 738 | case UNW_ARM_R11: _msContext.R11 = value; break; | |
| 739 | case UNW_ARM_R12: _msContext.R12 = value; break; | |
| 740 | case UNW_REG_SP: | |
| 741 | case UNW_ARM_SP: _msContext.Sp = value; break; | |
| 742 | case UNW_ARM_LR: _msContext.Lr = value; break; | |
| 743 | case UNW_REG_IP: | |
| 744 | case UNW_ARM_IP: _msContext.Pc = value; break; | |
| 745 | #elif defined(_LIBUNWIND_TARGET_AARCH64) | |
| 746 | case UNW_REG_SP: _msContext.Sp = value; break; | |
| 747 | case UNW_REG_IP: _msContext.Pc = value; break; | |
| 748 | case UNW_ARM64_X0: | |
| 749 | case UNW_ARM64_X1: | |
| 750 | case UNW_ARM64_X2: | |
| 751 | case UNW_ARM64_X3: | |
| 752 | case UNW_ARM64_X4: | |
| 753 | case UNW_ARM64_X5: | |
| 754 | case UNW_ARM64_X6: | |
| 755 | case UNW_ARM64_X7: | |
| 756 | case UNW_ARM64_X8: | |
| 757 | case UNW_ARM64_X9: | |
| 758 | case UNW_ARM64_X10: | |
| 759 | case UNW_ARM64_X11: | |
| 760 | case UNW_ARM64_X12: | |
| 761 | case UNW_ARM64_X13: | |
| 762 | case UNW_ARM64_X14: | |
| 763 | case UNW_ARM64_X15: | |
| 764 | case UNW_ARM64_X16: | |
| 765 | case UNW_ARM64_X17: | |
| 766 | case UNW_ARM64_X18: | |
| 767 | case UNW_ARM64_X19: | |
| 768 | case UNW_ARM64_X20: | |
| 769 | case UNW_ARM64_X21: | |
| 770 | case UNW_ARM64_X22: | |
| 771 | case UNW_ARM64_X23: | |
| 772 | case UNW_ARM64_X24: | |
| 773 | case UNW_ARM64_X25: | |
| 774 | case UNW_ARM64_X26: | |
| 775 | case UNW_ARM64_X27: | |
| 776 | case UNW_ARM64_X28: | |
| 777 | case UNW_ARM64_FP: | |
| 778 | case UNW_ARM64_LR: _msContext.X[regNum - UNW_ARM64_X0] = value; break; | |
| 779 | #endif | |
| 780 | default: | |
| 781 | _LIBUNWIND_ABORT("unsupported register"); | |
| 782 | } | |
| 783 | } | |
| 784 | ||
| 785 | template <typename A, typename R> | |
| 786 | bool UnwindCursor<A, R>::validFloatReg(int regNum) { | |
| 787 | #if defined(_LIBUNWIND_TARGET_ARM) | |
| 788 | if (regNum >= UNW_ARM_S0 && regNum <= UNW_ARM_S31) return true; | |
| 789 | if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D31) return true; | |
| 790 | #elif defined(_LIBUNWIND_TARGET_AARCH64) | |
| 791 | if (regNum >= UNW_ARM64_D0 && regNum <= UNW_ARM64_D31) return true; | |
| 792 | #endif | |
| 793 | return false; | |
| 794 | } | |
| 795 | ||
| 796 | template <typename A, typename R> | |
| 797 | unw_fpreg_t UnwindCursor<A, R>::getFloatReg(int regNum) { | |
| 798 | #if defined(_LIBUNWIND_TARGET_ARM) | |
| 799 | if (regNum >= UNW_ARM_S0 && regNum <= UNW_ARM_S31) { | |
| 800 | union { | |
| 801 | uint32_t w; | |
| 802 | float f; | |
| 803 | } d; | |
| 804 | d.w = _msContext.S[regNum - UNW_ARM_S0]; | |
| 805 | return d.f; | |
| 806 | } | |
| 807 | if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D31) { | |
| 808 | union { | |
| 809 | uint64_t w; | |
| 810 | double d; | |
| 811 | } d; | |
| 812 | d.w = _msContext.D[regNum - UNW_ARM_D0]; | |
| 813 | return d.d; | |
| 814 | } | |
| 815 | _LIBUNWIND_ABORT("unsupported float register"); | |
| 816 | #elif defined(_LIBUNWIND_TARGET_AARCH64) | |
| 817 | return _msContext.V[regNum - UNW_ARM64_D0].D[0]; | |
| 818 | #else | |
| 819 | _LIBUNWIND_ABORT("float registers unimplemented"); | |
| 820 | #endif | |
| 821 | } | |
| 822 | ||
| 823 | template <typename A, typename R> | |
| 824 | void UnwindCursor<A, R>::setFloatReg(int regNum, unw_fpreg_t value) { | |
| 825 | #if defined(_LIBUNWIND_TARGET_ARM) | |
| 826 | if (regNum >= UNW_ARM_S0 && regNum <= UNW_ARM_S31) { | |
| 827 | union { | |
| 828 | uint32_t w; | |
| 829 | float f; | |
| 830 | } d; | |
| 831 | d.f = value; | |
| 832 | _msContext.S[regNum - UNW_ARM_S0] = d.w; | |
| 833 | } | |
| 834 | if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D31) { | |
| 835 | union { | |
| 836 | uint64_t w; | |
| 837 | double d; | |
| 838 | } d; | |
| 839 | d.d = value; | |
| 840 | _msContext.D[regNum - UNW_ARM_D0] = d.w; | |
| 841 | } | |
| 842 | _LIBUNWIND_ABORT("unsupported float register"); | |
| 843 | #elif defined(_LIBUNWIND_TARGET_AARCH64) | |
| 844 | _msContext.V[regNum - UNW_ARM64_D0].D[0] = value; | |
| 845 | #else | |
| 846 | _LIBUNWIND_ABORT("float registers unimplemented"); | |
| 847 | #endif | |
| 848 | } | |
| 849 | ||
| 850 | template <typename A, typename R> void UnwindCursor<A, R>::jumpto() { | |
| 851 | RtlRestoreContext(&_msContext, nullptr); | |
| 852 | } | |
| 853 | ||
| 854 | #ifdef __arm__ | |
| 855 | template <typename A, typename R> void UnwindCursor<A, R>::saveVFPAsX() {} | |
| 856 | #endif | |
| 857 | ||
| 858 | template <typename A, typename R> | |
| 859 | const char *UnwindCursor<A, R>::getRegisterName(int regNum) { | |
| 860 | return R::getRegisterName(regNum); | |
| 861 | } | |
| 862 | ||
| 863 | template <typename A, typename R> bool UnwindCursor<A, R>::isSignalFrame() { | |
| 864 | return false; | |
| 865 | } | |
| 866 | ||
| 867 | #else // !defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) || !defined(_WIN32) | |
| 868 | ||
| 869 | /// UnwindCursor contains all state (including all register values) during | |
| 870 | /// an unwind. This is normally stack allocated inside a unw_cursor_t. | |
| 871 | template <typename A, typename R> | |
| 872 | class UnwindCursor : public AbstractUnwindCursor{ | |
| 873 | typedef typename A::pint_t pint_t; | |
| 874 | public: | |
| 875 | UnwindCursor(unw_context_t *context, A &as); | |
| 876 | UnwindCursor(A &as, void *threadArg); | |
| 877 | virtual ~UnwindCursor() {} | |
| 878 | virtual bool validReg(int); | |
| 879 | virtual unw_word_t getReg(int); | |
| 880 | virtual void setReg(int, unw_word_t); | |
| 881 | virtual bool validFloatReg(int); | |
| 882 | virtual unw_fpreg_t getFloatReg(int); | |
| 883 | virtual void setFloatReg(int, unw_fpreg_t); | |
| 884 | virtual int step(); | |
| 885 | virtual void getInfo(unw_proc_info_t *); | |
| 886 | virtual void jumpto(); | |
| 887 | virtual bool isSignalFrame(); | |
| 888 | virtual bool getFunctionName(char *buf, size_t len, unw_word_t *off); | |
| 889 | virtual void setInfoBasedOnIPRegister(bool isReturnAddress = false); | |
| 890 | virtual const char *getRegisterName(int num); | |
| 891 | #ifdef __arm__ | |
| 892 | virtual void saveVFPAsX(); | |
| 893 | #endif | |
| 894 | ||
| 895 | private: | |
| 896 | ||
| 897 | #if defined(_LIBUNWIND_ARM_EHABI) | |
| 898 | bool getInfoFromEHABISection(pint_t pc, const UnwindInfoSections &sects); | |
| 899 | ||
| 900 | int stepWithEHABI() { | |
| 901 | size_t len = 0; | |
| 902 | size_t off = 0; | |
| 903 | // FIXME: Calling decode_eht_entry() here is violating the libunwind | |
| 904 | // abstraction layer. | |
| 905 | const uint32_t *ehtp = | |
| 906 | decode_eht_entry(reinterpret_cast<const uint32_t *>(_info.unwind_info), | |
| 907 | &off, &len); | |
| 908 | if (_Unwind_VRS_Interpret((_Unwind_Context *)this, ehtp, off, len) != | |
| 909 | _URC_CONTINUE_UNWIND) | |
| 910 | return UNW_STEP_END; | |
| 911 | return UNW_STEP_SUCCESS; | |
| 912 | } | |
| 913 | #endif | |
| 914 | ||
| 915 | #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) | |
| 916 | bool getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections &sects, | |
| 917 | uint32_t fdeSectionOffsetHint=0); | |
| 918 | int stepWithDwarfFDE() { | |
| 919 | return DwarfInstructions<A, R>::stepWithDwarf(_addressSpace, | |
| 920 | (pint_t)this->getReg(UNW_REG_IP), | |
| 921 | (pint_t)_info.unwind_info, | |
| 922 | _registers); | |
| 923 | } | |
| 924 | #endif | |
| 925 | ||
| 926 | #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) | |
| 927 | bool getInfoFromCompactEncodingSection(pint_t pc, | |
| 928 | const UnwindInfoSections &sects); | |
| 929 | int stepWithCompactEncoding() { | |
| 930 | #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) | |
| 931 | if ( compactSaysUseDwarf() ) | |
| 932 | return stepWithDwarfFDE(); | |
| 933 | #endif | |
| 934 | R dummy; | |
| 935 | return stepWithCompactEncoding(dummy); | |
| 936 | } | |
| 937 | ||
| 938 | #if defined(_LIBUNWIND_TARGET_X86_64) | |
| 939 | int stepWithCompactEncoding(Registers_x86_64 &) { | |
| 940 | return CompactUnwinder_x86_64<A>::stepWithCompactEncoding( | |
| 941 | _info.format, _info.start_ip, _addressSpace, _registers); | |
| 942 | } | |
| 943 | #endif | |
| 944 | ||
| 945 | #if defined(_LIBUNWIND_TARGET_I386) | |
| 946 | int stepWithCompactEncoding(Registers_x86 &) { | |
| 947 | return CompactUnwinder_x86<A>::stepWithCompactEncoding( | |
| 948 | _info.format, (uint32_t)_info.start_ip, _addressSpace, _registers); | |
| 949 | } | |
| 950 | #endif | |
| 951 | ||
| 952 | #if defined(_LIBUNWIND_TARGET_PPC) | |
| 953 | int stepWithCompactEncoding(Registers_ppc &) { | |
| 954 | return UNW_EINVAL; | |
| 955 | } | |
| 956 | #endif | |
| 957 | ||
| 958 | #if defined(_LIBUNWIND_TARGET_PPC64) | |
| 959 | int stepWithCompactEncoding(Registers_ppc64 &) { | |
| 960 | return UNW_EINVAL; | |
| 961 | } | |
| 962 | #endif | |
| 963 | ||
| 964 | ||
| 965 | #if defined(_LIBUNWIND_TARGET_AARCH64) | |
| 966 | int stepWithCompactEncoding(Registers_arm64 &) { | |
| 967 | return CompactUnwinder_arm64<A>::stepWithCompactEncoding( | |
| 968 | _info.format, _info.start_ip, _addressSpace, _registers); | |
| 969 | } | |
| 970 | #endif | |
| 971 | ||
| 972 | #if defined(_LIBUNWIND_TARGET_MIPS_O32) | |
| 973 | int stepWithCompactEncoding(Registers_mips_o32 &) { | |
| 974 | return UNW_EINVAL; | |
| 975 | } | |
| 976 | #endif | |
| 977 | ||
| 978 | #if defined(_LIBUNWIND_TARGET_MIPS_NEWABI) | |
| 979 | int stepWithCompactEncoding(Registers_mips_newabi &) { | |
| 980 | return UNW_EINVAL; | |
| 981 | } | |
| 982 | #endif | |
| 983 | ||
| 984 | #if defined(_LIBUNWIND_TARGET_SPARC) | |
| 985 | int stepWithCompactEncoding(Registers_sparc &) { return UNW_EINVAL; } | |
| 986 | #endif | |
| 987 | ||
| 988 | bool compactSaysUseDwarf(uint32_t *offset=NULL) const { | |
| 989 | R dummy; | |
| 990 | return compactSaysUseDwarf(dummy, offset); | |
| 991 | } | |
| 992 | ||
| 993 | #if defined(_LIBUNWIND_TARGET_X86_64) | |
| 994 | bool compactSaysUseDwarf(Registers_x86_64 &, uint32_t *offset) const { | |
| 995 | if ((_info.format & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF) { | |
| 996 | if (offset) | |
| 997 | *offset = (_info.format & UNWIND_X86_64_DWARF_SECTION_OFFSET); | |
| 998 | return true; | |
| 999 | } | |
| 1000 | return false; | |
| 1001 | } | |
| 1002 | #endif | |
| 1003 | ||
| 1004 | #if defined(_LIBUNWIND_TARGET_I386) | |
| 1005 | bool compactSaysUseDwarf(Registers_x86 &, uint32_t *offset) const { | |
| 1006 | if ((_info.format & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF) { | |
| 1007 | if (offset) | |
| 1008 | *offset = (_info.format & UNWIND_X86_DWARF_SECTION_OFFSET); | |
| 1009 | return true; | |
| 1010 | } | |
| 1011 | return false; | |
| 1012 | } | |
| 1013 | #endif | |
| 1014 | ||
| 1015 | #if defined(_LIBUNWIND_TARGET_PPC) | |
| 1016 | bool compactSaysUseDwarf(Registers_ppc &, uint32_t *) const { | |
| 1017 | return true; | |
| 1018 | } | |
| 1019 | #endif | |
| 1020 | ||
| 1021 | #if defined(_LIBUNWIND_TARGET_PPC64) | |
| 1022 | bool compactSaysUseDwarf(Registers_ppc64 &, uint32_t *) const { | |
| 1023 | return true; | |
| 1024 | } | |
| 1025 | #endif | |
| 1026 | ||
| 1027 | #if defined(_LIBUNWIND_TARGET_AARCH64) | |
| 1028 | bool compactSaysUseDwarf(Registers_arm64 &, uint32_t *offset) const { | |
| 1029 | if ((_info.format & UNWIND_ARM64_MODE_MASK) == UNWIND_ARM64_MODE_DWARF) { | |
| 1030 | if (offset) | |
| 1031 | *offset = (_info.format & UNWIND_ARM64_DWARF_SECTION_OFFSET); | |
| 1032 | return true; | |
| 1033 | } | |
| 1034 | return false; | |
| 1035 | } | |
| 1036 | #endif | |
| 1037 | ||
| 1038 | #if defined(_LIBUNWIND_TARGET_MIPS_O32) | |
| 1039 | bool compactSaysUseDwarf(Registers_mips_o32 &, uint32_t *) const { | |
| 1040 | return true; | |
| 1041 | } | |
| 1042 | #endif | |
| 1043 | ||
| 1044 | #if defined(_LIBUNWIND_TARGET_MIPS_NEWABI) | |
| 1045 | bool compactSaysUseDwarf(Registers_mips_newabi &, uint32_t *) const { | |
| 1046 | return true; | |
| 1047 | } | |
| 1048 | #endif | |
| 1049 | ||
| 1050 | #if defined(_LIBUNWIND_TARGET_SPARC) | |
| 1051 | bool compactSaysUseDwarf(Registers_sparc &, uint32_t *) const { return true; } | |
| 1052 | #endif | |
| 1053 | ||
| 1054 | #endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) | |
| 1055 | ||
| 1056 | #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) | |
| 1057 | compact_unwind_encoding_t dwarfEncoding() const { | |
| 1058 | R dummy; | |
| 1059 | return dwarfEncoding(dummy); | |
| 1060 | } | |
| 1061 | ||
| 1062 | #if defined(_LIBUNWIND_TARGET_X86_64) | |
| 1063 | compact_unwind_encoding_t dwarfEncoding(Registers_x86_64 &) const { | |
| 1064 | return UNWIND_X86_64_MODE_DWARF; | |
| 1065 | } | |
| 1066 | #endif | |
| 1067 | ||
| 1068 | #if defined(_LIBUNWIND_TARGET_I386) | |
| 1069 | compact_unwind_encoding_t dwarfEncoding(Registers_x86 &) const { | |
| 1070 | return UNWIND_X86_MODE_DWARF; | |
| 1071 | } | |
| 1072 | #endif | |
| 1073 | ||
| 1074 | #if defined(_LIBUNWIND_TARGET_PPC) | |
| 1075 | compact_unwind_encoding_t dwarfEncoding(Registers_ppc &) const { | |
| 1076 | return 0; | |
| 1077 | } | |
| 1078 | #endif | |
| 1079 | ||
| 1080 | #if defined(_LIBUNWIND_TARGET_PPC64) | |
| 1081 | compact_unwind_encoding_t dwarfEncoding(Registers_ppc64 &) const { | |
| 1082 | return 0; | |
| 1083 | } | |
| 1084 | #endif | |
| 1085 | ||
| 1086 | #if defined(_LIBUNWIND_TARGET_AARCH64) | |
| 1087 | compact_unwind_encoding_t dwarfEncoding(Registers_arm64 &) const { | |
| 1088 | return UNWIND_ARM64_MODE_DWARF; | |
| 1089 | } | |
| 1090 | #endif | |
| 1091 | ||
| 1092 | #if defined(_LIBUNWIND_TARGET_ARM) | |
| 1093 | compact_unwind_encoding_t dwarfEncoding(Registers_arm &) const { | |
| 1094 | return 0; | |
| 1095 | } | |
| 1096 | #endif | |
| 1097 | ||
| 1098 | #if defined (_LIBUNWIND_TARGET_OR1K) | |
| 1099 | compact_unwind_encoding_t dwarfEncoding(Registers_or1k &) const { | |
| 1100 | return 0; | |
| 1101 | } | |
| 1102 | #endif | |
| 1103 | ||
| 1104 | #if defined (_LIBUNWIND_TARGET_MIPS_O32) | |
| 1105 | compact_unwind_encoding_t dwarfEncoding(Registers_mips_o32 &) const { | |
| 1106 | return 0; | |
| 1107 | } | |
| 1108 | #endif | |
| 1109 | ||
| 1110 | #if defined (_LIBUNWIND_TARGET_MIPS_NEWABI) | |
| 1111 | compact_unwind_encoding_t dwarfEncoding(Registers_mips_newabi &) const { | |
| 1112 | return 0; | |
| 1113 | } | |
| 1114 | #endif | |
| 1115 | ||
| 1116 | #if defined(_LIBUNWIND_TARGET_SPARC) | |
| 1117 | compact_unwind_encoding_t dwarfEncoding(Registers_sparc &) const { return 0; } | |
| 1118 | #endif | |
| 1119 | ||
| 1120 | #endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) | |
| 1121 | ||
| 1122 | #if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) | |
| 1123 | // For runtime environments using SEH unwind data without Windows runtime | |
| 1124 | // support. | |
| 1125 | pint_t getLastPC() const { /* FIXME: Implement */ return 0; } | |
| 1126 | void setLastPC(pint_t pc) { /* FIXME: Implement */ } | |
| 1127 | RUNTIME_FUNCTION *lookUpSEHUnwindInfo(pint_t pc, pint_t *base) { | |
| 1128 | /* FIXME: Implement */ | |
| 1129 | *base = 0; | |
| 1130 | return nullptr; | |
| 1131 | } | |
| 1132 | bool getInfoFromSEH(pint_t pc); | |
| 1133 | int stepWithSEHData() { /* FIXME: Implement */ return 0; } | |
| 1134 | #endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) | |
| 1135 | ||
| 1136 | ||
| 1137 | A &_addressSpace; | |
| 1138 | R _registers; | |
| 1139 | unw_proc_info_t _info; | |
| 1140 | bool _unwindInfoMissing; | |
| 1141 | bool _isSignalFrame; | |
| 1142 | }; | |
| 1143 | ||
| 1144 | ||
| 1145 | template <typename A, typename R> | |
| 1146 | UnwindCursor<A, R>::UnwindCursor(unw_context_t *context, A &as) | |
| 1147 | : _addressSpace(as), _registers(context), _unwindInfoMissing(false), | |
| 1148 | _isSignalFrame(false) { | |
| 1149 | static_assert((check_fit<UnwindCursor<A, R>, unw_cursor_t>::does_fit), | |
| 1150 | "UnwindCursor<> does not fit in unw_cursor_t"); | |
| 1151 | memset(&_info, 0, sizeof(_info)); | |
| 1152 | } | |
| 1153 | ||
| 1154 | template <typename A, typename R> | |
| 1155 | UnwindCursor<A, R>::UnwindCursor(A &as, void *) | |
| 1156 | : _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false) { | |
| 1157 | memset(&_info, 0, sizeof(_info)); | |
| 1158 | // FIXME | |
| 1159 | // fill in _registers from thread arg | |
| 1160 | } | |
| 1161 | ||
| 1162 | ||
| 1163 | template <typename A, typename R> | |
| 1164 | bool UnwindCursor<A, R>::validReg(int regNum) { | |
| 1165 | return _registers.validRegister(regNum); | |
| 1166 | } | |
| 1167 | ||
| 1168 | template <typename A, typename R> | |
| 1169 | unw_word_t UnwindCursor<A, R>::getReg(int regNum) { | |
| 1170 | return _registers.getRegister(regNum); | |
| 1171 | } | |
| 1172 | ||
| 1173 | template <typename A, typename R> | |
| 1174 | void UnwindCursor<A, R>::setReg(int regNum, unw_word_t value) { | |
| 1175 | _registers.setRegister(regNum, (typename A::pint_t)value); | |
| 1176 | } | |
| 1177 | ||
| 1178 | template <typename A, typename R> | |
| 1179 | bool UnwindCursor<A, R>::validFloatReg(int regNum) { | |
| 1180 | return _registers.validFloatRegister(regNum); | |
| 1181 | } | |
| 1182 | ||
| 1183 | template <typename A, typename R> | |
| 1184 | unw_fpreg_t UnwindCursor<A, R>::getFloatReg(int regNum) { | |
| 1185 | return _registers.getFloatRegister(regNum); | |
| 1186 | } | |
| 1187 | ||
| 1188 | template <typename A, typename R> | |
| 1189 | void UnwindCursor<A, R>::setFloatReg(int regNum, unw_fpreg_t value) { | |
| 1190 | _registers.setFloatRegister(regNum, value); | |
| 1191 | } | |
| 1192 | ||
| 1193 | template <typename A, typename R> void UnwindCursor<A, R>::jumpto() { | |
| 1194 | _registers.jumpto(); | |
| 1195 | } | |
| 1196 | ||
| 1197 | #ifdef __arm__ | |
| 1198 | template <typename A, typename R> void UnwindCursor<A, R>::saveVFPAsX() { | |
| 1199 | _registers.saveVFPAsX(); | |
| 1200 | } | |
| 1201 | #endif | |
| 1202 | ||
| 1203 | template <typename A, typename R> | |
| 1204 | const char *UnwindCursor<A, R>::getRegisterName(int regNum) { | |
| 1205 | return _registers.getRegisterName(regNum); | |
| 1206 | } | |
| 1207 | ||
| 1208 | template <typename A, typename R> bool UnwindCursor<A, R>::isSignalFrame() { | |
| 1209 | return _isSignalFrame; | |
| 1210 | } | |
| 1211 | ||
| 1212 | #endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) | |
| 1213 | ||
| 1214 | #if defined(_LIBUNWIND_ARM_EHABI) | |
| 1215 | struct EHABIIndexEntry { | |
| 1216 | uint32_t functionOffset; | |
| 1217 | uint32_t data; | |
| 1218 | }; | |
| 1219 | ||
| 1220 | template<typename A> | |
| 1221 | struct EHABISectionIterator { | |
| 1222 | typedef EHABISectionIterator _Self; | |
| 1223 | ||
| 1224 | typedef std::random_access_iterator_tag iterator_category; | |
| 1225 | typedef typename A::pint_t value_type; | |
| 1226 | typedef typename A::pint_t* pointer; | |
| 1227 | typedef typename A::pint_t& reference; | |
| 1228 | typedef size_t size_type; | |
| 1229 | typedef size_t difference_type; | |
| 1230 | ||
| 1231 | static _Self begin(A& addressSpace, const UnwindInfoSections& sects) { | |
| 1232 | return _Self(addressSpace, sects, 0); | |
| 1233 | } | |
| 1234 | static _Self end(A& addressSpace, const UnwindInfoSections& sects) { | |
| 1235 | return _Self(addressSpace, sects, | |
| 1236 | sects.arm_section_length / sizeof(EHABIIndexEntry)); | |
| 1237 | } | |
| 1238 | ||
| 1239 | EHABISectionIterator(A& addressSpace, const UnwindInfoSections& sects, size_t i) | |
| 1240 | : _i(i), _addressSpace(&addressSpace), _sects(&sects) {} | |
| 1241 | ||
| 1242 | _Self& operator++() { ++_i; return *this; } | |
| 1243 | _Self& operator+=(size_t a) { _i += a; return *this; } | |
| 1244 | _Self& operator--() { assert(_i > 0); --_i; return *this; } | |
| 1245 | _Self& operator-=(size_t a) { assert(_i >= a); _i -= a; return *this; } | |
| 1246 | ||
| 1247 | _Self operator+(size_t a) { _Self out = *this; out._i += a; return out; } | |
| 1248 | _Self operator-(size_t a) { assert(_i >= a); _Self out = *this; out._i -= a; return out; } | |
| 1249 | ||
| 1250 | size_t operator-(const _Self& other) { return _i - other._i; } | |
| 1251 | ||
| 1252 | bool operator==(const _Self& other) const { | |
| 1253 | assert(_addressSpace == other._addressSpace); | |
| 1254 | assert(_sects == other._sects); | |
| 1255 | return _i == other._i; | |
| 1256 | } | |
| 1257 | ||
| 1258 | typename A::pint_t operator*() const { return functionAddress(); } | |
| 1259 | ||
| 1260 | typename A::pint_t functionAddress() const { | |
| 1261 | typename A::pint_t indexAddr = _sects->arm_section + arrayoffsetof( | |
| 1262 | EHABIIndexEntry, _i, functionOffset); | |
| 1263 | return indexAddr + signExtendPrel31(_addressSpace->get32(indexAddr)); | |
| 1264 | } | |
| 1265 | ||
| 1266 | typename A::pint_t dataAddress() { | |
| 1267 | typename A::pint_t indexAddr = _sects->arm_section + arrayoffsetof( | |
| 1268 | EHABIIndexEntry, _i, data); | |
| 1269 | return indexAddr; | |
| 1270 | } | |
| 1271 | ||
| 1272 | private: | |
| 1273 | size_t _i; | |
| 1274 | A* _addressSpace; | |
| 1275 | const UnwindInfoSections* _sects; | |
| 1276 | }; | |
| 1277 | ||
| 1278 | template <typename A, typename R> | |
| 1279 | bool UnwindCursor<A, R>::getInfoFromEHABISection( | |
| 1280 | pint_t pc, | |
| 1281 | const UnwindInfoSections &sects) { | |
| 1282 | EHABISectionIterator<A> begin = | |
| 1283 | EHABISectionIterator<A>::begin(_addressSpace, sects); | |
| 1284 | EHABISectionIterator<A> end = | |
| 1285 | EHABISectionIterator<A>::end(_addressSpace, sects); | |
| 1286 | if (begin == end) | |
| 1287 | return false; | |
| 1288 | ||
| 1289 | EHABISectionIterator<A> itNextPC = std::upper_bound(begin, end, pc); | |
| 1290 | if (itNextPC == begin) | |
| 1291 | return false; | |
| 1292 | EHABISectionIterator<A> itThisPC = itNextPC - 1; | |
| 1293 | ||
| 1294 | pint_t thisPC = itThisPC.functionAddress(); | |
| 1295 | // If an exception is thrown from a function, corresponding to the last entry | |
| 1296 | // in the table, we don't really know the function extent and have to choose a | |
| 1297 | // value for nextPC. Choosing max() will allow the range check during trace to | |
| 1298 | // succeed. | |
| 1299 | pint_t nextPC = (itNextPC == end) ? std::numeric_limits<pint_t>::max() | |
| 1300 | : itNextPC.functionAddress(); | |
| 1301 | pint_t indexDataAddr = itThisPC.dataAddress(); | |
| 1302 | ||
| 1303 | if (indexDataAddr == 0) | |
| 1304 | return false; | |
| 1305 | ||
| 1306 | uint32_t indexData = _addressSpace.get32(indexDataAddr); | |
| 1307 | if (indexData == UNW_EXIDX_CANTUNWIND) | |
| 1308 | return false; | |
| 1309 | ||
| 1310 | // If the high bit is set, the exception handling table entry is inline inside | |
| 1311 | // the index table entry on the second word (aka |indexDataAddr|). Otherwise, | |
| 1312 | // the table points at an offset in the exception handling table (section 5 EHABI). | |
| 1313 | pint_t exceptionTableAddr; | |
| 1314 | uint32_t exceptionTableData; | |
| 1315 | bool isSingleWordEHT; | |
| 1316 | if (indexData & 0x80000000) { | |
| 1317 | exceptionTableAddr = indexDataAddr; | |
| 1318 | // TODO(ajwong): Should this data be 0? | |
| 1319 | exceptionTableData = indexData; | |
| 1320 | isSingleWordEHT = true; | |
| 1321 | } else { | |
| 1322 | exceptionTableAddr = indexDataAddr + signExtendPrel31(indexData); | |
| 1323 | exceptionTableData = _addressSpace.get32(exceptionTableAddr); | |
| 1324 | isSingleWordEHT = false; | |
| 1325 | } | |
| 1326 | ||
| 1327 | // Now we know the 3 things: | |
| 1328 | // exceptionTableAddr -- exception handler table entry. | |
| 1329 | // exceptionTableData -- the data inside the first word of the eht entry. | |
| 1330 | // isSingleWordEHT -- whether the entry is in the index. | |
| 1331 | unw_word_t personalityRoutine = 0xbadf00d; | |
| 1332 | bool scope32 = false; | |
| 1333 | uintptr_t lsda; | |
| 1334 | ||
| 1335 | // If the high bit in the exception handling table entry is set, the entry is | |
| 1336 | // in compact form (section 6.3 EHABI). | |
| 1337 | if (exceptionTableData & 0x80000000) { | |
| 1338 | // Grab the index of the personality routine from the compact form. | |
| 1339 | uint32_t choice = (exceptionTableData & 0x0f000000) >> 24; | |
| 1340 | uint32_t extraWords = 0; | |
| 1341 | switch (choice) { | |
| 1342 | case 0: | |
| 1343 | personalityRoutine = (unw_word_t) &__aeabi_unwind_cpp_pr0; | |
| 1344 | extraWords = 0; | |
| 1345 | scope32 = false; | |
| 1346 | lsda = isSingleWordEHT ? 0 : (exceptionTableAddr + 4); | |
| 1347 | break; | |
| 1348 | case 1: | |
| 1349 | personalityRoutine = (unw_word_t) &__aeabi_unwind_cpp_pr1; | |
| 1350 | extraWords = (exceptionTableData & 0x00ff0000) >> 16; | |
| 1351 | scope32 = false; | |
| 1352 | lsda = exceptionTableAddr + (extraWords + 1) * 4; | |
| 1353 | break; | |
| 1354 | case 2: | |
| 1355 | personalityRoutine = (unw_word_t) &__aeabi_unwind_cpp_pr2; | |
| 1356 | extraWords = (exceptionTableData & 0x00ff0000) >> 16; | |
| 1357 | scope32 = true; | |
| 1358 | lsda = exceptionTableAddr + (extraWords + 1) * 4; | |
| 1359 | break; | |
| 1360 | default: | |
| 1361 | _LIBUNWIND_ABORT("unknown personality routine"); | |
| 1362 | return false; | |
| 1363 | } | |
| 1364 | ||
| 1365 | if (isSingleWordEHT) { | |
| 1366 | if (extraWords != 0) { | |
| 1367 | _LIBUNWIND_ABORT("index inlined table detected but pr function " | |
| 1368 | "requires extra words"); | |
| 1369 | return false; | |
| 1370 | } | |
| 1371 | } | |
| 1372 | } else { | |
| 1373 | pint_t personalityAddr = | |
| 1374 | exceptionTableAddr + signExtendPrel31(exceptionTableData); | |
| 1375 | personalityRoutine = personalityAddr; | |
| 1376 | ||
| 1377 | // ARM EHABI # 6.2, # 9.2 | |
| 1378 | // | |
| 1379 | // +---- ehtp | |
| 1380 | // v | |
| 1381 | // +--------------------------------------+ | |
| 1382 | // | +--------+--------+--------+-------+ | | |
| 1383 | // | |0| prel31 to personalityRoutine | | | |
| 1384 | // | +--------+--------+--------+-------+ | | |
| 1385 | // | | N | unwind opcodes | | <-- UnwindData | |
| 1386 | // | +--------+--------+--------+-------+ | | |
| 1387 | // | | Word 2 unwind opcodes | | | |
| 1388 | // | +--------+--------+--------+-------+ | | |
| 1389 | // | ... | | |
| 1390 | // | +--------+--------+--------+-------+ | | |
| 1391 | // | | Word N unwind opcodes | | | |
| 1392 | // | +--------+--------+--------+-------+ | | |
| 1393 | // | | LSDA | | <-- lsda | |
| 1394 | // | | ... | | | |
| 1395 | // | +--------+--------+--------+-------+ | | |
| 1396 | // +--------------------------------------+ | |
| 1397 | ||
| 1398 | uint32_t *UnwindData = reinterpret_cast<uint32_t*>(exceptionTableAddr) + 1; | |
| 1399 | uint32_t FirstDataWord = *UnwindData; | |
| 1400 | size_t N = ((FirstDataWord >> 24) & 0xff); | |
| 1401 | size_t NDataWords = N + 1; | |
| 1402 | lsda = reinterpret_cast<uintptr_t>(UnwindData + NDataWords); | |
| 1403 | } | |
| 1404 | ||
| 1405 | _info.start_ip = thisPC; | |
| 1406 | _info.end_ip = nextPC; | |
| 1407 | _info.handler = personalityRoutine; | |
| 1408 | _info.unwind_info = exceptionTableAddr; | |
| 1409 | _info.lsda = lsda; | |
| 1410 | // flags is pr_cache.additional. See EHABI #7.2 for definition of bit 0. | |
| 1411 | _info.flags = isSingleWordEHT ? 1 : 0 | scope32 ? 0x2 : 0; // Use enum? | |
| 1412 | ||
| 1413 | return true; | |
| 1414 | } | |
| 1415 | #endif | |
| 1416 | ||
| 1417 | #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) | |
| 1418 | template <typename A, typename R> | |
| 1419 | bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc, | |
| 1420 | const UnwindInfoSections &sects, | |
| 1421 | uint32_t fdeSectionOffsetHint) { | |
| 1422 | typename CFI_Parser<A>::FDE_Info fdeInfo; | |
| 1423 | typename CFI_Parser<A>::CIE_Info cieInfo; | |
| 1424 | bool foundFDE = false; | |
| 1425 | bool foundInCache = false; | |
| 1426 | // If compact encoding table gave offset into dwarf section, go directly there | |
| 1427 | if (fdeSectionOffsetHint != 0) { | |
| 1428 | foundFDE = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section, | |
| 1429 | (uint32_t)sects.dwarf_section_length, | |
| 1430 | sects.dwarf_section + fdeSectionOffsetHint, | |
| 1431 | &fdeInfo, &cieInfo); | |
| 1432 | } | |
| 1433 | #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) | |
| 1434 | if (!foundFDE && (sects.dwarf_index_section != 0)) { | |
| 1435 | foundFDE = EHHeaderParser<A>::findFDE( | |
| 1436 | _addressSpace, pc, sects.dwarf_index_section, | |
| 1437 | (uint32_t)sects.dwarf_index_section_length, &fdeInfo, &cieInfo); | |
| 1438 | } | |
| 1439 | #endif | |
| 1440 | if (!foundFDE) { | |
| 1441 | // otherwise, search cache of previously found FDEs. | |
| 1442 | pint_t cachedFDE = DwarfFDECache<A>::findFDE(sects.dso_base, pc); | |
| 1443 | if (cachedFDE != 0) { | |
| 1444 | foundFDE = | |
| 1445 | CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section, | |
| 1446 | (uint32_t)sects.dwarf_section_length, | |
| 1447 | cachedFDE, &fdeInfo, &cieInfo); | |
| 1448 | foundInCache = foundFDE; | |
| 1449 | } | |
| 1450 | } | |
| 1451 | if (!foundFDE) { | |
| 1452 | // Still not found, do full scan of __eh_frame section. | |
| 1453 | foundFDE = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section, | |
| 1454 | (uint32_t)sects.dwarf_section_length, 0, | |
| 1455 | &fdeInfo, &cieInfo); | |
| 1456 | } | |
| 1457 | if (foundFDE) { | |
| 1458 | typename CFI_Parser<A>::PrologInfo prolog; | |
| 1459 | if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc, | |
| 1460 | R::getArch(), &prolog)) { | |
| 1461 | // Save off parsed FDE info | |
| 1462 | _info.start_ip = fdeInfo.pcStart; | |
| 1463 | _info.end_ip = fdeInfo.pcEnd; | |
| 1464 | _info.lsda = fdeInfo.lsda; | |
| 1465 | _info.handler = cieInfo.personality; | |
| 1466 | _info.gp = prolog.spExtraArgSize; | |
| 1467 | _info.flags = 0; | |
| 1468 | _info.format = dwarfEncoding(); | |
| 1469 | _info.unwind_info = fdeInfo.fdeStart; | |
| 1470 | _info.unwind_info_size = (uint32_t)fdeInfo.fdeLength; | |
| 1471 | _info.extra = (unw_word_t) sects.dso_base; | |
| 1472 | ||
| 1473 | // Add to cache (to make next lookup faster) if we had no hint | |
| 1474 | // and there was no index. | |
| 1475 | if (!foundInCache && (fdeSectionOffsetHint == 0)) { | |
| 1476 | #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) | |
| 1477 | if (sects.dwarf_index_section == 0) | |
| 1478 | #endif | |
| 1479 | DwarfFDECache<A>::add(sects.dso_base, fdeInfo.pcStart, fdeInfo.pcEnd, | |
| 1480 | fdeInfo.fdeStart); | |
| 1481 | } | |
| 1482 | return true; | |
| 1483 | } | |
| 1484 | } | |
| 1485 | //_LIBUNWIND_DEBUG_LOG("can't find/use FDE for pc=0x%llX", (uint64_t)pc); | |
| 1486 | return false; | |
| 1487 | } | |
| 1488 | #endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) | |
| 1489 | ||
| 1490 | ||
| 1491 | #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) | |
| 1492 | template <typename A, typename R> | |
| 1493 | bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(pint_t pc, | |
| 1494 | const UnwindInfoSections &sects) { | |
| 1495 | const bool log = false; | |
| 1496 | if (log) | |
| 1497 | fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX, mh=0x%llX)\n", | |
| 1498 | (uint64_t)pc, (uint64_t)sects.dso_base); | |
| 1499 | ||
| 1500 | const UnwindSectionHeader<A> sectionHeader(_addressSpace, | |
| 1501 | sects.compact_unwind_section); | |
| 1502 | if (sectionHeader.version() != UNWIND_SECTION_VERSION) | |
| 1503 | return false; | |
| 1504 | ||
| 1505 | // do a binary search of top level index to find page with unwind info | |
| 1506 | pint_t targetFunctionOffset = pc - sects.dso_base; | |
| 1507 | const UnwindSectionIndexArray<A> topIndex(_addressSpace, | |
| 1508 | sects.compact_unwind_section | |
| 1509 | + sectionHeader.indexSectionOffset()); | |
| 1510 | uint32_t low = 0; | |
| 1511 | uint32_t high = sectionHeader.indexCount(); | |
| 1512 | uint32_t last = high - 1; | |
| 1513 | while (low < high) { | |
| 1514 | uint32_t mid = (low + high) / 2; | |
| 1515 | //if ( log ) fprintf(stderr, "\tmid=%d, low=%d, high=%d, *mid=0x%08X\n", | |
| 1516 | //mid, low, high, topIndex.functionOffset(mid)); | |
| 1517 | if (topIndex.functionOffset(mid) <= targetFunctionOffset) { | |
| 1518 | if ((mid == last) || | |
| 1519 | (topIndex.functionOffset(mid + 1) > targetFunctionOffset)) { | |
| 1520 | low = mid; | |
| 1521 | break; | |
| 1522 | } else { | |
| 1523 | low = mid + 1; | |
| 1524 | } | |
| 1525 | } else { | |
| 1526 | high = mid; | |
| 1527 | } | |
| 1528 | } | |
| 1529 | const uint32_t firstLevelFunctionOffset = topIndex.functionOffset(low); | |
| 1530 | const uint32_t firstLevelNextPageFunctionOffset = | |
| 1531 | topIndex.functionOffset(low + 1); | |
| 1532 | const pint_t secondLevelAddr = | |
| 1533 | sects.compact_unwind_section + topIndex.secondLevelPagesSectionOffset(low); | |
| 1534 | const pint_t lsdaArrayStartAddr = | |
| 1535 | sects.compact_unwind_section + topIndex.lsdaIndexArraySectionOffset(low); | |
| 1536 | const pint_t lsdaArrayEndAddr = | |
| 1537 | sects.compact_unwind_section + topIndex.lsdaIndexArraySectionOffset(low+1); | |
| 1538 | if (log) | |
| 1539 | fprintf(stderr, "\tfirst level search for result index=%d " | |
| 1540 | "to secondLevelAddr=0x%llX\n", | |
| 1541 | low, (uint64_t) secondLevelAddr); | |
| 1542 | // do a binary search of second level page index | |
| 1543 | uint32_t encoding = 0; | |
| 1544 | pint_t funcStart = 0; | |
| 1545 | pint_t funcEnd = 0; | |
| 1546 | pint_t lsda = 0; | |
| 1547 | pint_t personality = 0; | |
| 1548 | uint32_t pageKind = _addressSpace.get32(secondLevelAddr); | |
| 1549 | if (pageKind == UNWIND_SECOND_LEVEL_REGULAR) { | |
| 1550 | // regular page | |
| 1551 | UnwindSectionRegularPageHeader<A> pageHeader(_addressSpace, | |
| 1552 | secondLevelAddr); | |
| 1553 | UnwindSectionRegularArray<A> pageIndex( | |
| 1554 | _addressSpace, secondLevelAddr + pageHeader.entryPageOffset()); | |
| 1555 | // binary search looks for entry with e where index[e].offset <= pc < | |
| 1556 | // index[e+1].offset | |
| 1557 | if (log) | |
| 1558 | fprintf(stderr, "\tbinary search for targetFunctionOffset=0x%08llX in " | |
| 1559 | "regular page starting at secondLevelAddr=0x%llX\n", | |
| 1560 | (uint64_t) targetFunctionOffset, (uint64_t) secondLevelAddr); | |
| 1561 | low = 0; | |
| 1562 | high = pageHeader.entryCount(); | |
| 1563 | while (low < high) { | |
| 1564 | uint32_t mid = (low + high) / 2; | |
| 1565 | if (pageIndex.functionOffset(mid) <= targetFunctionOffset) { | |
| 1566 | if (mid == (uint32_t)(pageHeader.entryCount() - 1)) { | |
| 1567 | // at end of table | |
| 1568 | low = mid; | |
| 1569 | funcEnd = firstLevelNextPageFunctionOffset + sects.dso_base; | |
| 1570 | break; | |
| 1571 | } else if (pageIndex.functionOffset(mid + 1) > targetFunctionOffset) { | |
| 1572 | // next is too big, so we found it | |
| 1573 | low = mid; | |
| 1574 | funcEnd = pageIndex.functionOffset(low + 1) + sects.dso_base; | |
| 1575 | break; | |
| 1576 | } else { | |
| 1577 | low = mid + 1; | |
| 1578 | } | |
| 1579 | } else { | |
| 1580 | high = mid; | |
| 1581 | } | |
| 1582 | } | |
| 1583 | encoding = pageIndex.encoding(low); | |
| 1584 | funcStart = pageIndex.functionOffset(low) + sects.dso_base; | |
| 1585 | if (pc < funcStart) { | |
| 1586 | if (log) | |
| 1587 | fprintf( | |
| 1588 | stderr, | |
| 1589 | "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n", | |
| 1590 | (uint64_t) pc, (uint64_t) funcStart, (uint64_t) funcEnd); | |
| 1591 | return false; | |
| 1592 | } | |
| 1593 | if (pc > funcEnd) { | |
| 1594 | if (log) | |
| 1595 | fprintf( | |
| 1596 | stderr, | |
| 1597 | "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n", | |
| 1598 | (uint64_t) pc, (uint64_t) funcStart, (uint64_t) funcEnd); | |
| 1599 | return false; | |
| 1600 | } | |
| 1601 | } else if (pageKind == UNWIND_SECOND_LEVEL_COMPRESSED) { | |
| 1602 | // compressed page | |
| 1603 | UnwindSectionCompressedPageHeader<A> pageHeader(_addressSpace, | |
| 1604 | secondLevelAddr); | |
| 1605 | UnwindSectionCompressedArray<A> pageIndex( | |
| 1606 | _addressSpace, secondLevelAddr + pageHeader.entryPageOffset()); | |
| 1607 | const uint32_t targetFunctionPageOffset = | |
| 1608 | (uint32_t)(targetFunctionOffset - firstLevelFunctionOffset); | |
| 1609 | // binary search looks for entry with e where index[e].offset <= pc < | |
| 1610 | // index[e+1].offset | |
| 1611 | if (log) | |
| 1612 | fprintf(stderr, "\tbinary search of compressed page starting at " | |
| 1613 | "secondLevelAddr=0x%llX\n", | |
| 1614 | (uint64_t) secondLevelAddr); | |
| 1615 | low = 0; | |
| 1616 | last = pageHeader.entryCount() - 1; | |
| 1617 | high = pageHeader.entryCount(); | |
| 1618 | while (low < high) { | |
| 1619 | uint32_t mid = (low + high) / 2; | |
| 1620 | if (pageIndex.functionOffset(mid) <= targetFunctionPageOffset) { | |
| 1621 | if ((mid == last) || | |
| 1622 | (pageIndex.functionOffset(mid + 1) > targetFunctionPageOffset)) { | |
| 1623 | low = mid; | |
| 1624 | break; | |
| 1625 | } else { | |
| 1626 | low = mid + 1; | |
| 1627 | } | |
| 1628 | } else { | |
| 1629 | high = mid; | |
| 1630 | } | |
| 1631 | } | |
| 1632 | funcStart = pageIndex.functionOffset(low) + firstLevelFunctionOffset | |
| 1633 | + sects.dso_base; | |
| 1634 | if (low < last) | |
| 1635 | funcEnd = | |
| 1636 | pageIndex.functionOffset(low + 1) + firstLevelFunctionOffset | |
| 1637 | + sects.dso_base; | |
| 1638 | else | |
| 1639 | funcEnd = firstLevelNextPageFunctionOffset + sects.dso_base; | |
| 1640 | if (pc < funcStart) { | |
| 1641 | _LIBUNWIND_DEBUG_LOG("malformed __unwind_info, pc=0x%llX not in second " | |
| 1642 | "level compressed unwind table. funcStart=0x%llX", | |
| 1643 | (uint64_t) pc, (uint64_t) funcStart); | |
| 1644 | return false; | |
| 1645 | } | |
| 1646 | if (pc > funcEnd) { | |
| 1647 | _LIBUNWIND_DEBUG_LOG("malformed __unwind_info, pc=0x%llX not in second " | |
| 1648 | "level compressed unwind table. funcEnd=0x%llX", | |
| 1649 | (uint64_t) pc, (uint64_t) funcEnd); | |
| 1650 | return false; | |
| 1651 | } | |
| 1652 | uint16_t encodingIndex = pageIndex.encodingIndex(low); | |
| 1653 | if (encodingIndex < sectionHeader.commonEncodingsArrayCount()) { | |
| 1654 | // encoding is in common table in section header | |
| 1655 | encoding = _addressSpace.get32( | |
| 1656 | sects.compact_unwind_section + | |
| 1657 | sectionHeader.commonEncodingsArraySectionOffset() + | |
| 1658 | encodingIndex * sizeof(uint32_t)); | |
| 1659 | } else { | |
| 1660 | // encoding is in page specific table | |
| 1661 | uint16_t pageEncodingIndex = | |
| 1662 | encodingIndex - (uint16_t)sectionHeader.commonEncodingsArrayCount(); | |
| 1663 | encoding = _addressSpace.get32(secondLevelAddr + | |
| 1664 | pageHeader.encodingsPageOffset() + | |
| 1665 | pageEncodingIndex * sizeof(uint32_t)); | |
| 1666 | } | |
| 1667 | } else { | |
| 1668 | _LIBUNWIND_DEBUG_LOG("malformed __unwind_info at 0x%0llX bad second " | |
| 1669 | "level page", | |
| 1670 | (uint64_t) sects.compact_unwind_section); | |
| 1671 | return false; | |
| 1672 | } | |
| 1673 | ||
| 1674 | // look up LSDA, if encoding says function has one | |
| 1675 | if (encoding & UNWIND_HAS_LSDA) { | |
| 1676 | UnwindSectionLsdaArray<A> lsdaIndex(_addressSpace, lsdaArrayStartAddr); | |
| 1677 | uint32_t funcStartOffset = (uint32_t)(funcStart - sects.dso_base); | |
| 1678 | low = 0; | |
| 1679 | high = (uint32_t)(lsdaArrayEndAddr - lsdaArrayStartAddr) / | |
| 1680 | sizeof(unwind_info_section_header_lsda_index_entry); | |
| 1681 | // binary search looks for entry with exact match for functionOffset | |
| 1682 | if (log) | |
| 1683 | fprintf(stderr, | |
| 1684 | "\tbinary search of lsda table for targetFunctionOffset=0x%08X\n", | |
| 1685 | funcStartOffset); | |
| 1686 | while (low < high) { | |
| 1687 | uint32_t mid = (low + high) / 2; | |
| 1688 | if (lsdaIndex.functionOffset(mid) == funcStartOffset) { | |
| 1689 | lsda = lsdaIndex.lsdaOffset(mid) + sects.dso_base; | |
| 1690 | break; | |
| 1691 | } else if (lsdaIndex.functionOffset(mid) < funcStartOffset) { | |
| 1692 | low = mid + 1; | |
| 1693 | } else { | |
| 1694 | high = mid; | |
| 1695 | } | |
| 1696 | } | |
| 1697 | if (lsda == 0) { | |
| 1698 | _LIBUNWIND_DEBUG_LOG("found encoding 0x%08X with HAS_LSDA bit set for " | |
| 1699 | "pc=0x%0llX, but lsda table has no entry", | |
| 1700 | encoding, (uint64_t) pc); | |
| 1701 | return false; | |
| 1702 | } | |
| 1703 | } | |
| 1704 | ||
| 1705 | // extact personality routine, if encoding says function has one | |
| 1706 | uint32_t personalityIndex = (encoding & UNWIND_PERSONALITY_MASK) >> | |
| 1707 | (__builtin_ctz(UNWIND_PERSONALITY_MASK)); | |
| 1708 | if (personalityIndex != 0) { | |
| 1709 | --personalityIndex; // change 1-based to zero-based index | |
| 1710 | if (personalityIndex > sectionHeader.personalityArrayCount()) { | |
| 1711 | _LIBUNWIND_DEBUG_LOG("found encoding 0x%08X with personality index %d, " | |
| 1712 | "but personality table has only %d entires", | |
| 1713 | encoding, personalityIndex, | |
| 1714 | sectionHeader.personalityArrayCount()); | |
| 1715 | return false; | |
| 1716 | } | |
| 1717 | int32_t personalityDelta = (int32_t)_addressSpace.get32( | |
| 1718 | sects.compact_unwind_section + | |
| 1719 | sectionHeader.personalityArraySectionOffset() + | |
| 1720 | personalityIndex * sizeof(uint32_t)); | |
| 1721 | pint_t personalityPointer = sects.dso_base + (pint_t)personalityDelta; | |
| 1722 | personality = _addressSpace.getP(personalityPointer); | |
| 1723 | if (log) | |
| 1724 | fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), " | |
| 1725 | "personalityDelta=0x%08X, personality=0x%08llX\n", | |
| 1726 | (uint64_t) pc, personalityDelta, (uint64_t) personality); | |
| 1727 | } | |
| 1728 | ||
| 1729 | if (log) | |
| 1730 | fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), " | |
| 1731 | "encoding=0x%08X, lsda=0x%08llX for funcStart=0x%llX\n", | |
| 1732 | (uint64_t) pc, encoding, (uint64_t) lsda, (uint64_t) funcStart); | |
| 1733 | _info.start_ip = funcStart; | |
| 1734 | _info.end_ip = funcEnd; | |
| 1735 | _info.lsda = lsda; | |
| 1736 | _info.handler = personality; | |
| 1737 | _info.gp = 0; | |
| 1738 | _info.flags = 0; | |
| 1739 | _info.format = encoding; | |
| 1740 | _info.unwind_info = 0; | |
| 1741 | _info.unwind_info_size = 0; | |
| 1742 | _info.extra = sects.dso_base; | |
| 1743 | return true; | |
| 1744 | } | |
| 1745 | #endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) | |
| 1746 | ||
| 1747 | ||
| 1748 | #if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) | |
| 1749 | template <typename A, typename R> | |
| 1750 | bool UnwindCursor<A, R>::getInfoFromSEH(pint_t pc) { | |
| 1751 | pint_t base; | |
| 1752 | RUNTIME_FUNCTION *unwindEntry = lookUpSEHUnwindInfo(pc, &base); | |
| 1753 | if (!unwindEntry) { | |
| 1754 | _LIBUNWIND_DEBUG_LOG("\tpc not in table, pc=0x%llX", (uint64_t) pc); | |
| 1755 | return false; | |
| 1756 | } | |
| 1757 | _info.gp = 0; | |
| 1758 | _info.flags = 0; | |
| 1759 | _info.format = 0; | |
| 1760 | _info.unwind_info_size = sizeof(RUNTIME_FUNCTION); | |
| 1761 | _info.unwind_info = reinterpret_cast<unw_word_t>(unwindEntry); | |
| 1762 | _info.extra = base; | |
| 1763 | _info.start_ip = base + unwindEntry->BeginAddress; | |
| 1764 | #ifdef _LIBUNWIND_TARGET_X86_64 | |
| 1765 | _info.end_ip = base + unwindEntry->EndAddress; | |
| 1766 | // Only fill in the handler and LSDA if they're stale. | |
| 1767 | if (pc != getLastPC()) { | |
| 1768 | UNWIND_INFO *xdata = reinterpret_cast<UNWIND_INFO *>(base + unwindEntry->UnwindData); | |
| 1769 | if (xdata->Flags & (UNW_FLAG_EHANDLER|UNW_FLAG_UHANDLER)) { | |
| 1770 | // The personality is given in the UNWIND_INFO itself. The LSDA immediately | |
| 1771 | // follows the UNWIND_INFO. (This follows how both Clang and MSVC emit | |
| 1772 | // these structures.) | |
| 1773 | // N.B. UNWIND_INFO structs are DWORD-aligned. | |
| 1774 | uint32_t lastcode = (xdata->CountOfCodes + 1) & ~1; | |
| 1775 | const uint32_t *handler = reinterpret_cast<uint32_t *>(&xdata->UnwindCodes[lastcode]); | |
| 1776 | _info.lsda = reinterpret_cast<unw_word_t>(handler+1); | |
| 1777 | if (*handler) { | |
| 1778 | _info.handler = reinterpret_cast<unw_word_t>(__libunwind_seh_personality); | |
| 1779 | } else | |
| 1780 | _info.handler = 0; | |
| 1781 | } else { | |
| 1782 | _info.lsda = 0; | |
| 1783 | _info.handler = 0; | |
| 1784 | } | |
| 1785 | } | |
| 1786 | #elif defined(_LIBUNWIND_TARGET_ARM) | |
| 1787 | _info.end_ip = _info.start_ip + unwindEntry->FunctionLength; | |
| 1788 | _info.lsda = 0; // FIXME | |
| 1789 | _info.handler = 0; // FIXME | |
| 1790 | #endif | |
| 1791 | setLastPC(pc); | |
| 1792 | return true; | |
| 1793 | } | |
| 1794 | #endif | |
| 1795 | ||
| 1796 | ||
| 1797 | template <typename A, typename R> | |
| 1798 | void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) { | |
| 1799 | pint_t pc = (pint_t)this->getReg(UNW_REG_IP); | |
| 1800 | #if defined(_LIBUNWIND_ARM_EHABI) | |
| 1801 | // Remove the thumb bit so the IP represents the actual instruction address. | |
| 1802 | // This matches the behaviour of _Unwind_GetIP on arm. | |
| 1803 | pc &= (pint_t)~0x1; | |
| 1804 | #endif | |
| 1805 | ||
| 1806 | // If the last line of a function is a "throw" the compiler sometimes | |
| 1807 | // emits no instructions after the call to __cxa_throw. This means | |
| 1808 | // the return address is actually the start of the next function. | |
| 1809 | // To disambiguate this, back up the pc when we know it is a return | |
| 1810 | // address. | |
| 1811 | if (isReturnAddress) | |
| 1812 | --pc; | |
| 1813 | ||
| 1814 | // Ask address space object to find unwind sections for this pc. | |
| 1815 | UnwindInfoSections sects; | |
| 1816 | if (_addressSpace.findUnwindSections(pc, sects)) { | |
| 1817 | #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) | |
| 1818 | // If there is a compact unwind encoding table, look there first. | |
| 1819 | if (sects.compact_unwind_section != 0) { | |
| 1820 | if (this->getInfoFromCompactEncodingSection(pc, sects)) { | |
| 1821 | #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) | |
| 1822 | // Found info in table, done unless encoding says to use dwarf. | |
| 1823 | uint32_t dwarfOffset; | |
| 1824 | if ((sects.dwarf_section != 0) && compactSaysUseDwarf(&dwarfOffset)) { | |
| 1825 | if (this->getInfoFromDwarfSection(pc, sects, dwarfOffset)) { | |
| 1826 | // found info in dwarf, done | |
| 1827 | return; | |
| 1828 | } | |
| 1829 | } | |
| 1830 | #endif | |
| 1831 | // If unwind table has entry, but entry says there is no unwind info, | |
| 1832 | // record that we have no unwind info. | |
| 1833 | if (_info.format == 0) | |
| 1834 | _unwindInfoMissing = true; | |
| 1835 | return; | |
| 1836 | } | |
| 1837 | } | |
| 1838 | #endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) | |
| 1839 | ||
| 1840 | #if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) | |
| 1841 | // If there is SEH unwind info, look there next. | |
| 1842 | if (this->getInfoFromSEH(pc)) | |
| 1843 | return; | |
| 1844 | #endif | |
| 1845 | ||
| 1846 | #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) | |
| 1847 | // If there is dwarf unwind info, look there next. | |
| 1848 | if (sects.dwarf_section != 0) { | |
| 1849 | if (this->getInfoFromDwarfSection(pc, sects)) { | |
| 1850 | // found info in dwarf, done | |
| 1851 | return; | |
| 1852 | } | |
| 1853 | } | |
| 1854 | #endif | |
| 1855 | ||
| 1856 | #if defined(_LIBUNWIND_ARM_EHABI) | |
| 1857 | // If there is ARM EHABI unwind info, look there next. | |
| 1858 | if (sects.arm_section != 0 && this->getInfoFromEHABISection(pc, sects)) | |
| 1859 | return; | |
| 1860 | #endif | |
| 1861 | } | |
| 1862 | ||
| 1863 | #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) | |
| 1864 | // There is no static unwind info for this pc. Look to see if an FDE was | |
| 1865 | // dynamically registered for it. | |
| 1866 | pint_t cachedFDE = DwarfFDECache<A>::findFDE(0, pc); | |
| 1867 | if (cachedFDE != 0) { | |
| 1868 | CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo; | |
| 1869 | CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo; | |
| 1870 | const char *msg = CFI_Parser<A>::decodeFDE(_addressSpace, | |
| 1871 | cachedFDE, &fdeInfo, &cieInfo); | |
| 1872 | if (msg == NULL) { | |
| 1873 | typename CFI_Parser<A>::PrologInfo prolog; | |
| 1874 | if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, | |
| 1875 | pc, R::getArch(), &prolog)) { | |
| 1876 | // save off parsed FDE info | |
| 1877 | _info.start_ip = fdeInfo.pcStart; | |
| 1878 | _info.end_ip = fdeInfo.pcEnd; | |
| 1879 | _info.lsda = fdeInfo.lsda; | |
| 1880 | _info.handler = cieInfo.personality; | |
| 1881 | _info.gp = prolog.spExtraArgSize; | |
| 1882 | // Some frameless functions need SP | |
| 1883 | // altered when resuming in function. | |
| 1884 | _info.flags = 0; | |
| 1885 | _info.format = dwarfEncoding(); | |
| 1886 | _info.unwind_info = fdeInfo.fdeStart; | |
| 1887 | _info.unwind_info_size = (uint32_t)fdeInfo.fdeLength; | |
| 1888 | _info.extra = 0; | |
| 1889 | return; | |
| 1890 | } | |
| 1891 | } | |
| 1892 | } | |
| 1893 | ||
| 1894 | // Lastly, ask AddressSpace object about platform specific ways to locate | |
| 1895 | // other FDEs. | |
| 1896 | pint_t fde; | |
| 1897 | if (_addressSpace.findOtherFDE(pc, fde)) { | |
| 1898 | CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo; | |
| 1899 | CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo; | |
| 1900 | if (!CFI_Parser<A>::decodeFDE(_addressSpace, fde, &fdeInfo, &cieInfo)) { | |
| 1901 | // Double check this FDE is for a function that includes the pc. | |
| 1902 | if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd)) { | |
| 1903 | typename CFI_Parser<A>::PrologInfo prolog; | |
| 1904 | if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, | |
| 1905 | pc, R::getArch(), &prolog)) { | |
| 1906 | // save off parsed FDE info | |
| 1907 | _info.start_ip = fdeInfo.pcStart; | |
| 1908 | _info.end_ip = fdeInfo.pcEnd; | |
| 1909 | _info.lsda = fdeInfo.lsda; | |
| 1910 | _info.handler = cieInfo.personality; | |
| 1911 | _info.gp = prolog.spExtraArgSize; | |
| 1912 | _info.flags = 0; | |
| 1913 | _info.format = dwarfEncoding(); | |
| 1914 | _info.unwind_info = fdeInfo.fdeStart; | |
| 1915 | _info.unwind_info_size = (uint32_t)fdeInfo.fdeLength; | |
| 1916 | _info.extra = 0; | |
| 1917 | return; | |
| 1918 | } | |
| 1919 | } | |
| 1920 | } | |
| 1921 | } | |
| 1922 | #endif // #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) | |
| 1923 | ||
| 1924 | // no unwind info, flag that we can't reliably unwind | |
| 1925 | _unwindInfoMissing = true; | |
| 1926 | } | |
| 1927 | ||
| 1928 | template <typename A, typename R> | |
| 1929 | int UnwindCursor<A, R>::step() { | |
| 1930 | // Bottom of stack is defined is when unwind info cannot be found. | |
| 1931 | if (_unwindInfoMissing) | |
| 1932 | return UNW_STEP_END; | |
| 1933 | ||
| 1934 | // Use unwinding info to modify register set as if function returned. | |
| 1935 | int result; | |
| 1936 | #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) | |
| 1937 | result = this->stepWithCompactEncoding(); | |
| 1938 | #elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) | |
| 1939 | result = this->stepWithSEHData(); | |
| 1940 | #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) | |
| 1941 | result = this->stepWithDwarfFDE(); | |
| 1942 | #elif defined(_LIBUNWIND_ARM_EHABI) | |
| 1943 | result = this->stepWithEHABI(); | |
| 1944 | #else | |
| 1945 | #error Need _LIBUNWIND_SUPPORT_COMPACT_UNWIND or \ | |
| 1946 | _LIBUNWIND_SUPPORT_SEH_UNWIND or \ | |
| 1947 | _LIBUNWIND_SUPPORT_DWARF_UNWIND or \ | |
| 1948 | _LIBUNWIND_ARM_EHABI | |
| 1949 | #endif | |
| 1950 | ||
| 1951 | // update info based on new PC | |
| 1952 | if (result == UNW_STEP_SUCCESS) { | |
| 1953 | this->setInfoBasedOnIPRegister(true); | |
| 1954 | if (_unwindInfoMissing) | |
| 1955 | return UNW_STEP_END; | |
| 1956 | } | |
| 1957 | ||
| 1958 | return result; | |
| 1959 | } | |
| 1960 | ||
| 1961 | template <typename A, typename R> | |
| 1962 | void UnwindCursor<A, R>::getInfo(unw_proc_info_t *info) { | |
| 1963 | *info = _info; | |
| 1964 | } | |
| 1965 | ||
| 1966 | template <typename A, typename R> | |
| 1967 | bool UnwindCursor<A, R>::getFunctionName(char *buf, size_t bufLen, | |
| 1968 | unw_word_t *offset) { | |
| 1969 | return _addressSpace.findFunctionName((pint_t)this->getReg(UNW_REG_IP), | |
| 1970 | buf, bufLen, offset); | |
| 1971 | } | |
| 1972 | ||
| 1973 | } // namespace libunwind | |
| 1974 | ||
| 1975 | #endif // __UNWINDCURSOR_HPP__ |
libunwind/src/UnwindLevel1-gcc-ext.c created+320| ... | ... | @@ -0,0 +1,320 @@ |
| 1 | //===--------------------- UnwindLevel1-gcc-ext.c -------------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is dual licensed under the MIT and the University of Illinois Open | |
| 6 | // Source Licenses. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | // | |
| 9 | // Implements gcc extensions to the C++ ABI Exception Handling Level 1. | |
| 10 | // | |
| 11 | //===----------------------------------------------------------------------===// | |
| 12 | ||
| 13 | #include <inttypes.h> | |
| 14 | #include <stdbool.h> | |
| 15 | #include <stdint.h> | |
| 16 | #include <stdio.h> | |
| 17 | #include <stdlib.h> | |
| 18 | #include <string.h> | |
| 19 | ||
| 20 | #include "config.h" | |
| 21 | #include "libunwind_ext.h" | |
| 22 | #include "libunwind.h" | |
| 23 | #include "Unwind-EHABI.h" | |
| 24 | #include "unwind.h" | |
| 25 | ||
| 26 | #if defined(_LIBUNWIND_BUILD_ZERO_COST_APIS) | |
| 27 | ||
| 28 | #if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) | |
| 29 | #define private_1 private_[0] | |
| 30 | #endif | |
| 31 | ||
| 32 | /// Called by __cxa_rethrow(). | |
| 33 | _LIBUNWIND_EXPORT _Unwind_Reason_Code | |
| 34 | _Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object) { | |
| 35 | #if defined(_LIBUNWIND_ARM_EHABI) | |
| 36 | _LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%ld", | |
| 37 | (void *)exception_object, | |
| 38 | (long)exception_object->unwinder_cache.reserved1); | |
| 39 | #else | |
| 40 | _LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%" PRIdPTR, | |
| 41 | (void *)exception_object, | |
| 42 | (intptr_t)exception_object->private_1); | |
| 43 | #endif | |
| 44 | ||
| 45 | #if defined(_LIBUNWIND_ARM_EHABI) | |
| 46 | // _Unwind_RaiseException on EHABI will always set the reserved1 field to 0, | |
| 47 | // which is in the same position as private_1 below. | |
| 48 | return _Unwind_RaiseException(exception_object); | |
| 49 | #else | |
| 50 | // If this is non-forced and a stopping place was found, then this is a | |
| 51 | // re-throw. | |
| 52 | // Call _Unwind_RaiseException() as if this was a new exception | |
| 53 | if (exception_object->private_1 == 0) { | |
| 54 | return _Unwind_RaiseException(exception_object); | |
| 55 | // Will return if there is no catch clause, so that __cxa_rethrow can call | |
| 56 | // std::terminate(). | |
| 57 | } | |
| 58 | ||
| 59 | // Call through to _Unwind_Resume() which distiguishes between forced and | |
| 60 | // regular exceptions. | |
| 61 | _Unwind_Resume(exception_object); | |
| 62 | _LIBUNWIND_ABORT("_Unwind_Resume_or_Rethrow() called _Unwind_RaiseException()" | |
| 63 | " which unexpectedly returned"); | |
| 64 | #endif | |
| 65 | } | |
| 66 | ||
| 67 | ||
| 68 | /// Called by personality handler during phase 2 to get base address for data | |
| 69 | /// relative encodings. | |
| 70 | _LIBUNWIND_EXPORT uintptr_t | |
| 71 | _Unwind_GetDataRelBase(struct _Unwind_Context *context) { | |
| 72 | (void)context; | |
| 73 | _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", (void *)context); | |
| 74 | _LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented"); | |
| 75 | } | |
| 76 | ||
| 77 | ||
| 78 | /// Called by personality handler during phase 2 to get base address for text | |
| 79 | /// relative encodings. | |
| 80 | _LIBUNWIND_EXPORT uintptr_t | |
| 81 | _Unwind_GetTextRelBase(struct _Unwind_Context *context) { | |
| 82 | (void)context; | |
| 83 | _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)", (void *)context); | |
| 84 | _LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented"); | |
| 85 | } | |
| 86 | ||
| 87 | ||
| 88 | /// Scans unwind information to find the function that contains the | |
| 89 | /// specified code address "pc". | |
| 90 | _LIBUNWIND_EXPORT void *_Unwind_FindEnclosingFunction(void *pc) { | |
| 91 | _LIBUNWIND_TRACE_API("_Unwind_FindEnclosingFunction(pc=%p)", pc); | |
| 92 | // This is slow, but works. | |
| 93 | // We create an unwind cursor then alter the IP to be pc | |
| 94 | unw_cursor_t cursor; | |
| 95 | unw_context_t uc; | |
| 96 | unw_proc_info_t info; | |
| 97 | unw_getcontext(&uc); | |
| 98 | unw_init_local(&cursor, &uc); | |
| 99 | unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(intptr_t) pc); | |
| 100 | if (unw_get_proc_info(&cursor, &info) == UNW_ESUCCESS) | |
| 101 | return (void *)(intptr_t) info.start_ip; | |
| 102 | else | |
| 103 | return NULL; | |
| 104 | } | |
| 105 | ||
| 106 | /// Walk every frame and call trace function at each one. If trace function | |
| 107 | /// returns anything other than _URC_NO_REASON, then walk is terminated. | |
| 108 | _LIBUNWIND_EXPORT _Unwind_Reason_Code | |
| 109 | _Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) { | |
| 110 | unw_cursor_t cursor; | |
| 111 | unw_context_t uc; | |
| 112 | unw_getcontext(&uc); | |
| 113 | unw_init_local(&cursor, &uc); | |
| 114 | ||
| 115 | _LIBUNWIND_TRACE_API("_Unwind_Backtrace(callback=%p)", | |
| 116 | (void *)(uintptr_t)callback); | |
| 117 | ||
| 118 | #if defined(_LIBUNWIND_ARM_EHABI) | |
| 119 | // Create a mock exception object for force unwinding. | |
| 120 | _Unwind_Exception ex; | |
| 121 | memset(&ex, '\0', sizeof(ex)); | |
| 122 | ex.exception_class = 0x434C4E47554E5700; // CLNGUNW\0 | |
| 123 | #endif | |
| 124 | ||
| 125 | // walk each frame | |
| 126 | while (true) { | |
| 127 | _Unwind_Reason_Code result; | |
| 128 | ||
| 129 | #if !defined(_LIBUNWIND_ARM_EHABI) | |
| 130 | // ask libunwind to get next frame (skip over first frame which is | |
| 131 | // _Unwind_Backtrace()) | |
| 132 | if (unw_step(&cursor) <= 0) { | |
| 133 | _LIBUNWIND_TRACE_UNWINDING(" _backtrace: ended because cursor reached " | |
| 134 | "bottom of stack, returning %d", | |
| 135 | _URC_END_OF_STACK); | |
| 136 | return _URC_END_OF_STACK; | |
| 137 | } | |
| 138 | #else | |
| 139 | // Get the information for this frame. | |
| 140 | unw_proc_info_t frameInfo; | |
| 141 | if (unw_get_proc_info(&cursor, &frameInfo) != UNW_ESUCCESS) { | |
| 142 | return _URC_END_OF_STACK; | |
| 143 | } | |
| 144 | ||
| 145 | // Update the pr_cache in the mock exception object. | |
| 146 | const uint32_t* unwindInfo = (uint32_t *) frameInfo.unwind_info; | |
| 147 | ex.pr_cache.fnstart = frameInfo.start_ip; | |
| 148 | ex.pr_cache.ehtp = (_Unwind_EHT_Header *) unwindInfo; | |
| 149 | ex.pr_cache.additional= frameInfo.flags; | |
| 150 | ||
| 151 | struct _Unwind_Context *context = (struct _Unwind_Context *)&cursor; | |
| 152 | // Get and call the personality function to unwind the frame. | |
| 153 | __personality_routine handler = (__personality_routine) frameInfo.handler; | |
| 154 | if (handler == NULL) { | |
| 155 | return _URC_END_OF_STACK; | |
| 156 | } | |
| 157 | if (handler(_US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND, &ex, context) != | |
| 158 | _URC_CONTINUE_UNWIND) { | |
| 159 | return _URC_END_OF_STACK; | |
| 160 | } | |
| 161 | #endif // defined(_LIBUNWIND_ARM_EHABI) | |
| 162 | ||
| 163 | // debugging | |
| 164 | if (_LIBUNWIND_TRACING_UNWINDING) { | |
| 165 | char functionName[512]; | |
| 166 | unw_proc_info_t frame; | |
| 167 | unw_word_t offset; | |
| 168 | unw_get_proc_name(&cursor, functionName, 512, &offset); | |
| 169 | unw_get_proc_info(&cursor, &frame); | |
| 170 | _LIBUNWIND_TRACE_UNWINDING( | |
| 171 | " _backtrace: start_ip=0x%" PRIxPTR ", func=%s, lsda=0x%" PRIxPTR ", context=%p", | |
| 172 | frame.start_ip, functionName, frame.lsda, | |
| 173 | (void *)&cursor); | |
| 174 | } | |
| 175 | ||
| 176 | // call trace function with this frame | |
| 177 | result = (*callback)((struct _Unwind_Context *)(&cursor), ref); | |
| 178 | if (result != _URC_NO_REASON) { | |
| 179 | _LIBUNWIND_TRACE_UNWINDING( | |
| 180 | " _backtrace: ended because callback returned %d", result); | |
| 181 | return result; | |
| 182 | } | |
| 183 | } | |
| 184 | } | |
| 185 | ||
| 186 | ||
| 187 | /// Find DWARF unwind info for an address 'pc' in some function. | |
| 188 | _LIBUNWIND_EXPORT const void *_Unwind_Find_FDE(const void *pc, | |
| 189 | struct dwarf_eh_bases *bases) { | |
| 190 | // This is slow, but works. | |
| 191 | // We create an unwind cursor then alter the IP to be pc | |
| 192 | unw_cursor_t cursor; | |
| 193 | unw_context_t uc; | |
| 194 | unw_proc_info_t info; | |
| 195 | unw_getcontext(&uc); | |
| 196 | unw_init_local(&cursor, &uc); | |
| 197 | unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(intptr_t) pc); | |
| 198 | unw_get_proc_info(&cursor, &info); | |
| 199 | bases->tbase = (uintptr_t)info.extra; | |
| 200 | bases->dbase = 0; // dbase not used on Mac OS X | |
| 201 | bases->func = (uintptr_t)info.start_ip; | |
| 202 | _LIBUNWIND_TRACE_API("_Unwind_Find_FDE(pc=%p) => %p", pc, | |
| 203 | (void *)(intptr_t) info.unwind_info); | |
| 204 | return (void *)(intptr_t) info.unwind_info; | |
| 205 | } | |
| 206 | ||
| 207 | /// Returns the CFA (call frame area, or stack pointer at start of function) | |
| 208 | /// for the current context. | |
| 209 | _LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) { | |
| 210 | unw_cursor_t *cursor = (unw_cursor_t *)context; | |
| 211 | unw_word_t result; | |
| 212 | unw_get_reg(cursor, UNW_REG_SP, &result); | |
| 213 | _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p) => 0x%" PRIxPTR, | |
| 214 | (void *)context, result); | |
| 215 | return (uintptr_t)result; | |
| 216 | } | |
| 217 | ||
| 218 | ||
| 219 | /// Called by personality handler during phase 2 to get instruction pointer. | |
| 220 | /// ipBefore is a boolean that says if IP is already adjusted to be the call | |
| 221 | /// site address. Normally IP is the return address. | |
| 222 | _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context, | |
| 223 | int *ipBefore) { | |
| 224 | _LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p)", (void *)context); | |
| 225 | *ipBefore = 0; | |
| 226 | return _Unwind_GetIP(context); | |
| 227 | } | |
| 228 | ||
| 229 | #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) | |
| 230 | ||
| 231 | /// Called by programs with dynamic code generators that want | |
| 232 | /// to register a dynamically generated FDE. | |
| 233 | /// This function has existed on Mac OS X since 10.4, but | |
| 234 | /// was broken until 10.6. | |
| 235 | _LIBUNWIND_EXPORT void __register_frame(const void *fde) { | |
| 236 | _LIBUNWIND_TRACE_API("__register_frame(%p)", fde); | |
| 237 | _unw_add_dynamic_fde((unw_word_t)(uintptr_t) fde); | |
| 238 | } | |
| 239 | ||
| 240 | ||
| 241 | /// Called by programs with dynamic code generators that want | |
| 242 | /// to unregister a dynamically generated FDE. | |
| 243 | /// This function has existed on Mac OS X since 10.4, but | |
| 244 | /// was broken until 10.6. | |
| 245 | _LIBUNWIND_EXPORT void __deregister_frame(const void *fde) { | |
| 246 | _LIBUNWIND_TRACE_API("__deregister_frame(%p)", fde); | |
| 247 | _unw_remove_dynamic_fde((unw_word_t)(uintptr_t) fde); | |
| 248 | } | |
| 249 | ||
| 250 | ||
| 251 | // The following register/deregister functions are gcc extensions. | |
| 252 | // They have existed on Mac OS X, but have never worked because Mac OS X | |
| 253 | // before 10.6 used keymgr to track known FDEs, but these functions | |
| 254 | // never got updated to use keymgr. | |
| 255 | // For now, we implement these as do-nothing functions to keep any existing | |
| 256 | // applications working. We also add the not in 10.6 symbol so that nwe | |
| 257 | // application won't be able to use them. | |
| 258 | ||
| 259 | #if defined(_LIBUNWIND_SUPPORT_FRAME_APIS) | |
| 260 | _LIBUNWIND_EXPORT void __register_frame_info_bases(const void *fde, void *ob, | |
| 261 | void *tb, void *db) { | |
| 262 | (void)fde; | |
| 263 | (void)ob; | |
| 264 | (void)tb; | |
| 265 | (void)db; | |
| 266 | _LIBUNWIND_TRACE_API("__register_frame_info_bases(%p,%p, %p, %p)", | |
| 267 | fde, ob, tb, db); | |
| 268 | // do nothing, this function never worked in Mac OS X | |
| 269 | } | |
| 270 | ||
| 271 | _LIBUNWIND_EXPORT void __register_frame_info(const void *fde, void *ob) { | |
| 272 | (void)fde; | |
| 273 | (void)ob; | |
| 274 | _LIBUNWIND_TRACE_API("__register_frame_info(%p, %p)", fde, ob); | |
| 275 | // do nothing, this function never worked in Mac OS X | |
| 276 | } | |
| 277 | ||
| 278 | _LIBUNWIND_EXPORT void __register_frame_info_table_bases(const void *fde, | |
| 279 | void *ob, void *tb, | |
| 280 | void *db) { | |
| 281 | (void)fde; | |
| 282 | (void)ob; | |
| 283 | (void)tb; | |
| 284 | (void)db; | |
| 285 | _LIBUNWIND_TRACE_API("__register_frame_info_table_bases" | |
| 286 | "(%p,%p, %p, %p)", fde, ob, tb, db); | |
| 287 | // do nothing, this function never worked in Mac OS X | |
| 288 | } | |
| 289 | ||
| 290 | _LIBUNWIND_EXPORT void __register_frame_info_table(const void *fde, void *ob) { | |
| 291 | (void)fde; | |
| 292 | (void)ob; | |
| 293 | _LIBUNWIND_TRACE_API("__register_frame_info_table(%p, %p)", fde, ob); | |
| 294 | // do nothing, this function never worked in Mac OS X | |
| 295 | } | |
| 296 | ||
| 297 | _LIBUNWIND_EXPORT void __register_frame_table(const void *fde) { | |
| 298 | (void)fde; | |
| 299 | _LIBUNWIND_TRACE_API("__register_frame_table(%p)", fde); | |
| 300 | // do nothing, this function never worked in Mac OS X | |
| 301 | } | |
| 302 | ||
| 303 | _LIBUNWIND_EXPORT void *__deregister_frame_info(const void *fde) { | |
| 304 | (void)fde; | |
| 305 | _LIBUNWIND_TRACE_API("__deregister_frame_info(%p)", fde); | |
| 306 | // do nothing, this function never worked in Mac OS X | |
| 307 | return NULL; | |
| 308 | } | |
| 309 | ||
| 310 | _LIBUNWIND_EXPORT void *__deregister_frame_info_bases(const void *fde) { | |
| 311 | (void)fde; | |
| 312 | _LIBUNWIND_TRACE_API("__deregister_frame_info_bases(%p)", fde); | |
| 313 | // do nothing, this function never worked in Mac OS X | |
| 314 | return NULL; | |
| 315 | } | |
| 316 | #endif // defined(_LIBUNWIND_SUPPORT_FRAME_APIS) | |
| 317 | ||
| 318 | #endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) | |
| 319 | ||
| 320 | #endif // defined(_LIBUNWIND_BUILD_ZERO_COST_APIS) |
libunwind/src/UnwindLevel1.c created+509| ... | ... | @@ -0,0 +1,509 @@ |
| 1 | //===------------------------- UnwindLevel1.c -----------------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is dual licensed under the MIT and the University of Illinois Open | |
| 6 | // Source Licenses. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | // | |
| 9 | // Implements C++ ABI Exception Handling Level 1 as documented at: | |
| 10 | // http://mentorembedded.github.io/cxx-abi/abi-eh.html | |
| 11 | // using libunwind | |
| 12 | // | |
| 13 | //===----------------------------------------------------------------------===// | |
| 14 | ||
| 15 | // ARM EHABI does not specify _Unwind_{Get,Set}{GR,IP}(). Thus, we are | |
| 16 | // defining inline functions to delegate the function calls to | |
| 17 | // _Unwind_VRS_{Get,Set}(). However, some applications might declare the | |
| 18 | // function protetype directly (instead of including <unwind.h>), thus we need | |
| 19 | // to export these functions from libunwind.so as well. | |
| 20 | #define _LIBUNWIND_UNWIND_LEVEL1_EXTERNAL_LINKAGE 1 | |
| 21 | ||
| 22 | #include <inttypes.h> | |
| 23 | #include <stdint.h> | |
| 24 | #include <stdbool.h> | |
| 25 | #include <stdlib.h> | |
| 26 | #include <stdio.h> | |
| 27 | #include <string.h> | |
| 28 | ||
| 29 | #include "libunwind.h" | |
| 30 | #include "unwind.h" | |
| 31 | #include "config.h" | |
| 32 | ||
| 33 | #if !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__) | |
| 34 | ||
| 35 | #ifndef _LIBUNWIND_SUPPORT_SEH_UNWIND | |
| 36 | ||
| 37 | static _Unwind_Reason_Code | |
| 38 | unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) { | |
| 39 | unw_init_local(cursor, uc); | |
| 40 | ||
| 41 | // Walk each frame looking for a place to stop. | |
| 42 | bool handlerNotFound = true; | |
| 43 | while (handlerNotFound) { | |
| 44 | // Ask libunwind to get next frame (skip over first which is | |
| 45 | // _Unwind_RaiseException). | |
| 46 | int stepResult = unw_step(cursor); | |
| 47 | if (stepResult == 0) { | |
| 48 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step() reached " | |
| 49 | "bottom => _URC_END_OF_STACK", | |
| 50 | (void *)exception_object); | |
| 51 | return _URC_END_OF_STACK; | |
| 52 | } else if (stepResult < 0) { | |
| 53 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step failed => " | |
| 54 | "_URC_FATAL_PHASE1_ERROR", | |
| 55 | (void *)exception_object); | |
| 56 | return _URC_FATAL_PHASE1_ERROR; | |
| 57 | } | |
| 58 | ||
| 59 | // See if frame has code to run (has personality routine). | |
| 60 | unw_proc_info_t frameInfo; | |
| 61 | unw_word_t sp; | |
| 62 | if (unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { | |
| 63 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_get_proc_info " | |
| 64 | "failed => _URC_FATAL_PHASE1_ERROR", | |
| 65 | (void *)exception_object); | |
| 66 | return _URC_FATAL_PHASE1_ERROR; | |
| 67 | } | |
| 68 | ||
| 69 | // When tracing, print state information. | |
| 70 | if (_LIBUNWIND_TRACING_UNWINDING) { | |
| 71 | char functionBuf[512]; | |
| 72 | const char *functionName = functionBuf; | |
| 73 | unw_word_t offset; | |
| 74 | if ((unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), | |
| 75 | &offset) != UNW_ESUCCESS) || | |
| 76 | (frameInfo.start_ip + offset > frameInfo.end_ip)) | |
| 77 | functionName = ".anonymous."; | |
| 78 | unw_word_t pc; | |
| 79 | unw_get_reg(cursor, UNW_REG_IP, &pc); | |
| 80 | _LIBUNWIND_TRACE_UNWINDING( | |
| 81 | "unwind_phase1(ex_ojb=%p): pc=0x%" PRIxPTR ", start_ip=0x%" PRIxPTR | |
| 82 | ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR "", | |
| 83 | (void *)exception_object, pc, frameInfo.start_ip, functionName, | |
| 84 | frameInfo.lsda, frameInfo.handler); | |
| 85 | } | |
| 86 | ||
| 87 | // If there is a personality routine, ask it if it will want to stop at | |
| 88 | // this frame. | |
| 89 | if (frameInfo.handler != 0) { | |
| 90 | __personality_routine p = | |
| 91 | (__personality_routine)(uintptr_t)(frameInfo.handler); | |
| 92 | _LIBUNWIND_TRACE_UNWINDING( | |
| 93 | "unwind_phase1(ex_ojb=%p): calling personality function %p", | |
| 94 | (void *)exception_object, (void *)(uintptr_t)p); | |
| 95 | _Unwind_Reason_Code personalityResult = | |
| 96 | (*p)(1, _UA_SEARCH_PHASE, exception_object->exception_class, | |
| 97 | exception_object, (struct _Unwind_Context *)(cursor)); | |
| 98 | switch (personalityResult) { | |
| 99 | case _URC_HANDLER_FOUND: | |
| 100 | // found a catch clause or locals that need destructing in this frame | |
| 101 | // stop search and remember stack pointer at the frame | |
| 102 | handlerNotFound = false; | |
| 103 | unw_get_reg(cursor, UNW_REG_SP, &sp); | |
| 104 | exception_object->private_2 = (uintptr_t)sp; | |
| 105 | _LIBUNWIND_TRACE_UNWINDING( | |
| 106 | "unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND", | |
| 107 | (void *)exception_object); | |
| 108 | return _URC_NO_REASON; | |
| 109 | ||
| 110 | case _URC_CONTINUE_UNWIND: | |
| 111 | _LIBUNWIND_TRACE_UNWINDING( | |
| 112 | "unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND", | |
| 113 | (void *)exception_object); | |
| 114 | // continue unwinding | |
| 115 | break; | |
| 116 | ||
| 117 | default: | |
| 118 | // something went wrong | |
| 119 | _LIBUNWIND_TRACE_UNWINDING( | |
| 120 | "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR", | |
| 121 | (void *)exception_object); | |
| 122 | return _URC_FATAL_PHASE1_ERROR; | |
| 123 | } | |
| 124 | } | |
| 125 | } | |
| 126 | return _URC_NO_REASON; | |
| 127 | } | |
| 128 | ||
| 129 | ||
| 130 | static _Unwind_Reason_Code | |
| 131 | unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) { | |
| 132 | unw_init_local(cursor, uc); | |
| 133 | ||
| 134 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)", | |
| 135 | (void *)exception_object); | |
| 136 | ||
| 137 | // Walk each frame until we reach where search phase said to stop. | |
| 138 | while (true) { | |
| 139 | ||
| 140 | // Ask libunwind to get next frame (skip over first which is | |
| 141 | // _Unwind_RaiseException). | |
| 142 | int stepResult = unw_step(cursor); | |
| 143 | if (stepResult == 0) { | |
| 144 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached " | |
| 145 | "bottom => _URC_END_OF_STACK", | |
| 146 | (void *)exception_object); | |
| 147 | return _URC_END_OF_STACK; | |
| 148 | } else if (stepResult < 0) { | |
| 149 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step failed => " | |
| 150 | "_URC_FATAL_PHASE1_ERROR", | |
| 151 | (void *)exception_object); | |
| 152 | return _URC_FATAL_PHASE2_ERROR; | |
| 153 | } | |
| 154 | ||
| 155 | // Get info about this frame. | |
| 156 | unw_word_t sp; | |
| 157 | unw_proc_info_t frameInfo; | |
| 158 | unw_get_reg(cursor, UNW_REG_SP, &sp); | |
| 159 | if (unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { | |
| 160 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_get_proc_info " | |
| 161 | "failed => _URC_FATAL_PHASE1_ERROR", | |
| 162 | (void *)exception_object); | |
| 163 | return _URC_FATAL_PHASE2_ERROR; | |
| 164 | } | |
| 165 | ||
| 166 | // When tracing, print state information. | |
| 167 | if (_LIBUNWIND_TRACING_UNWINDING) { | |
| 168 | char functionBuf[512]; | |
| 169 | const char *functionName = functionBuf; | |
| 170 | unw_word_t offset; | |
| 171 | if ((unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), | |
| 172 | &offset) != UNW_ESUCCESS) || | |
| 173 | (frameInfo.start_ip + offset > frameInfo.end_ip)) | |
| 174 | functionName = ".anonymous."; | |
| 175 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIxPTR | |
| 176 | ", func=%s, sp=0x%" PRIxPTR ", lsda=0x%" PRIxPTR | |
| 177 | ", personality=0x%" PRIxPTR, | |
| 178 | (void *)exception_object, frameInfo.start_ip, | |
| 179 | functionName, sp, frameInfo.lsda, | |
| 180 | frameInfo.handler); | |
| 181 | } | |
| 182 | ||
| 183 | // If there is a personality routine, tell it we are unwinding. | |
| 184 | if (frameInfo.handler != 0) { | |
| 185 | __personality_routine p = | |
| 186 | (__personality_routine)(uintptr_t)(frameInfo.handler); | |
| 187 | _Unwind_Action action = _UA_CLEANUP_PHASE; | |
| 188 | if (sp == exception_object->private_2) { | |
| 189 | // Tell personality this was the frame it marked in phase 1. | |
| 190 | action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME); | |
| 191 | } | |
| 192 | _Unwind_Reason_Code personalityResult = | |
| 193 | (*p)(1, action, exception_object->exception_class, exception_object, | |
| 194 | (struct _Unwind_Context *)(cursor)); | |
| 195 | switch (personalityResult) { | |
| 196 | case _URC_CONTINUE_UNWIND: | |
| 197 | // Continue unwinding | |
| 198 | _LIBUNWIND_TRACE_UNWINDING( | |
| 199 | "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND", | |
| 200 | (void *)exception_object); | |
| 201 | if (sp == exception_object->private_2) { | |
| 202 | // Phase 1 said we would stop at this frame, but we did not... | |
| 203 | _LIBUNWIND_ABORT("during phase1 personality function said it would " | |
| 204 | "stop here, but now in phase2 it did not stop here"); | |
| 205 | } | |
| 206 | break; | |
| 207 | case _URC_INSTALL_CONTEXT: | |
| 208 | _LIBUNWIND_TRACE_UNWINDING( | |
| 209 | "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT", | |
| 210 | (void *)exception_object); | |
| 211 | // Personality routine says to transfer control to landing pad. | |
| 212 | // We may get control back if landing pad calls _Unwind_Resume(). | |
| 213 | if (_LIBUNWIND_TRACING_UNWINDING) { | |
| 214 | unw_word_t pc; | |
| 215 | unw_get_reg(cursor, UNW_REG_IP, &pc); | |
| 216 | unw_get_reg(cursor, UNW_REG_SP, &sp); | |
| 217 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering " | |
| 218 | "user code with ip=0x%" PRIxPTR | |
| 219 | ", sp=0x%" PRIxPTR, | |
| 220 | (void *)exception_object, pc, sp); | |
| 221 | } | |
| 222 | unw_resume(cursor); | |
| 223 | // unw_resume() only returns if there was an error. | |
| 224 | return _URC_FATAL_PHASE2_ERROR; | |
| 225 | default: | |
| 226 | // Personality routine returned an unknown result code. | |
| 227 | _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d", | |
| 228 | personalityResult); | |
| 229 | return _URC_FATAL_PHASE2_ERROR; | |
| 230 | } | |
| 231 | } | |
| 232 | } | |
| 233 | ||
| 234 | // Clean up phase did not resume at the frame that the search phase | |
| 235 | // said it would... | |
| 236 | return _URC_FATAL_PHASE2_ERROR; | |
| 237 | } | |
| 238 | ||
| 239 | static _Unwind_Reason_Code | |
| 240 | unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor, | |
| 241 | _Unwind_Exception *exception_object, | |
| 242 | _Unwind_Stop_Fn stop, void *stop_parameter) { | |
| 243 | unw_init_local(cursor, uc); | |
| 244 | ||
| 245 | // Walk each frame until we reach where search phase said to stop | |
| 246 | while (unw_step(cursor) > 0) { | |
| 247 | ||
| 248 | // Update info about this frame. | |
| 249 | unw_proc_info_t frameInfo; | |
| 250 | if (unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { | |
| 251 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): unw_step " | |
| 252 | "failed => _URC_END_OF_STACK", | |
| 253 | (void *)exception_object); | |
| 254 | return _URC_FATAL_PHASE2_ERROR; | |
| 255 | } | |
| 256 | ||
| 257 | // When tracing, print state information. | |
| 258 | if (_LIBUNWIND_TRACING_UNWINDING) { | |
| 259 | char functionBuf[512]; | |
| 260 | const char *functionName = functionBuf; | |
| 261 | unw_word_t offset; | |
| 262 | if ((unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), | |
| 263 | &offset) != UNW_ESUCCESS) || | |
| 264 | (frameInfo.start_ip + offset > frameInfo.end_ip)) | |
| 265 | functionName = ".anonymous."; | |
| 266 | _LIBUNWIND_TRACE_UNWINDING( | |
| 267 | "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIxPTR | |
| 268 | ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR, | |
| 269 | (void *)exception_object, frameInfo.start_ip, functionName, | |
| 270 | frameInfo.lsda, frameInfo.handler); | |
| 271 | } | |
| 272 | ||
| 273 | // Call stop function at each frame. | |
| 274 | _Unwind_Action action = | |
| 275 | (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE); | |
| 276 | _Unwind_Reason_Code stopResult = | |
| 277 | (*stop)(1, action, exception_object->exception_class, exception_object, | |
| 278 | (struct _Unwind_Context *)(cursor), stop_parameter); | |
| 279 | _LIBUNWIND_TRACE_UNWINDING( | |
| 280 | "unwind_phase2_forced(ex_ojb=%p): stop function returned %d", | |
| 281 | (void *)exception_object, stopResult); | |
| 282 | if (stopResult != _URC_NO_REASON) { | |
| 283 | _LIBUNWIND_TRACE_UNWINDING( | |
| 284 | "unwind_phase2_forced(ex_ojb=%p): stopped by stop function", | |
| 285 | (void *)exception_object); | |
| 286 | return _URC_FATAL_PHASE2_ERROR; | |
| 287 | } | |
| 288 | ||
| 289 | // If there is a personality routine, tell it we are unwinding. | |
| 290 | if (frameInfo.handler != 0) { | |
| 291 | __personality_routine p = | |
| 292 | (__personality_routine)(intptr_t)(frameInfo.handler); | |
| 293 | _LIBUNWIND_TRACE_UNWINDING( | |
| 294 | "unwind_phase2_forced(ex_ojb=%p): calling personality function %p", | |
| 295 | (void *)exception_object, (void *)(uintptr_t)p); | |
| 296 | _Unwind_Reason_Code personalityResult = | |
| 297 | (*p)(1, action, exception_object->exception_class, exception_object, | |
| 298 | (struct _Unwind_Context *)(cursor)); | |
| 299 | switch (personalityResult) { | |
| 300 | case _URC_CONTINUE_UNWIND: | |
| 301 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " | |
| 302 | "personality returned " | |
| 303 | "_URC_CONTINUE_UNWIND", | |
| 304 | (void *)exception_object); | |
| 305 | // Destructors called, continue unwinding | |
| 306 | break; | |
| 307 | case _URC_INSTALL_CONTEXT: | |
| 308 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " | |
| 309 | "personality returned " | |
| 310 | "_URC_INSTALL_CONTEXT", | |
| 311 | (void *)exception_object); | |
| 312 | // We may get control back if landing pad calls _Unwind_Resume(). | |
| 313 | unw_resume(cursor); | |
| 314 | break; | |
| 315 | default: | |
| 316 | // Personality routine returned an unknown result code. | |
| 317 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " | |
| 318 | "personality returned %d, " | |
| 319 | "_URC_FATAL_PHASE2_ERROR", | |
| 320 | (void *)exception_object, personalityResult); | |
| 321 | return _URC_FATAL_PHASE2_ERROR; | |
| 322 | } | |
| 323 | } | |
| 324 | } | |
| 325 | ||
| 326 | // Call stop function one last time and tell it we've reached the end | |
| 327 | // of the stack. | |
| 328 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop " | |
| 329 | "function with _UA_END_OF_STACK", | |
| 330 | (void *)exception_object); | |
| 331 | _Unwind_Action lastAction = | |
| 332 | (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK); | |
| 333 | (*stop)(1, lastAction, exception_object->exception_class, exception_object, | |
| 334 | (struct _Unwind_Context *)(cursor), stop_parameter); | |
| 335 | ||
| 336 | // Clean up phase did not resume at the frame that the search phase said it | |
| 337 | // would. | |
| 338 | return _URC_FATAL_PHASE2_ERROR; | |
| 339 | } | |
| 340 | ||
| 341 | ||
| 342 | /// Called by __cxa_throw. Only returns if there is a fatal error. | |
| 343 | _LIBUNWIND_EXPORT _Unwind_Reason_Code | |
| 344 | _Unwind_RaiseException(_Unwind_Exception *exception_object) { | |
| 345 | _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)", | |
| 346 | (void *)exception_object); | |
| 347 | unw_context_t uc; | |
| 348 | unw_cursor_t cursor; | |
| 349 | unw_getcontext(&uc); | |
| 350 | ||
| 351 | // Mark that this is a non-forced unwind, so _Unwind_Resume() | |
| 352 | // can do the right thing. | |
| 353 | exception_object->private_1 = 0; | |
| 354 | exception_object->private_2 = 0; | |
| 355 | ||
| 356 | // phase 1: the search phase | |
| 357 | _Unwind_Reason_Code phase1 = unwind_phase1(&uc, &cursor, exception_object); | |
| 358 | if (phase1 != _URC_NO_REASON) | |
| 359 | return phase1; | |
| 360 | ||
| 361 | // phase 2: the clean up phase | |
| 362 | return unwind_phase2(&uc, &cursor, exception_object); | |
| 363 | } | |
| 364 | ||
| 365 | ||
| 366 | ||
| 367 | /// When _Unwind_RaiseException() is in phase2, it hands control | |
| 368 | /// to the personality function at each frame. The personality | |
| 369 | /// may force a jump to a landing pad in that function, the landing | |
| 370 | /// pad code may then call _Unwind_Resume() to continue with the | |
| 371 | /// unwinding. Note: the call to _Unwind_Resume() is from compiler | |
| 372 | /// geneated user code. All other _Unwind_* routines are called | |
| 373 | /// by the C++ runtime __cxa_* routines. | |
| 374 | /// | |
| 375 | /// Note: re-throwing an exception (as opposed to continuing the unwind) | |
| 376 | /// is implemented by having the code call __cxa_rethrow() which | |
| 377 | /// in turn calls _Unwind_Resume_or_Rethrow(). | |
| 378 | _LIBUNWIND_EXPORT void | |
| 379 | _Unwind_Resume(_Unwind_Exception *exception_object) { | |
| 380 | _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)", (void *)exception_object); | |
| 381 | unw_context_t uc; | |
| 382 | unw_cursor_t cursor; | |
| 383 | unw_getcontext(&uc); | |
| 384 | ||
| 385 | if (exception_object->private_1 != 0) | |
| 386 | unwind_phase2_forced(&uc, &cursor, exception_object, | |
| 387 | (_Unwind_Stop_Fn) exception_object->private_1, | |
| 388 | (void *)exception_object->private_2); | |
| 389 | else | |
| 390 | unwind_phase2(&uc, &cursor, exception_object); | |
| 391 | ||
| 392 | // Clients assume _Unwind_Resume() does not return, so all we can do is abort. | |
| 393 | _LIBUNWIND_ABORT("_Unwind_Resume() can't return"); | |
| 394 | } | |
| 395 | ||
| 396 | ||
| 397 | ||
| 398 | /// Not used by C++. | |
| 399 | /// Unwinds stack, calling "stop" function at each frame. | |
| 400 | /// Could be used to implement longjmp(). | |
| 401 | _LIBUNWIND_EXPORT _Unwind_Reason_Code | |
| 402 | _Unwind_ForcedUnwind(_Unwind_Exception *exception_object, | |
| 403 | _Unwind_Stop_Fn stop, void *stop_parameter) { | |
| 404 | _LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)", | |
| 405 | (void *)exception_object, (void *)(uintptr_t)stop); | |
| 406 | unw_context_t uc; | |
| 407 | unw_cursor_t cursor; | |
| 408 | unw_getcontext(&uc); | |
| 409 | ||
| 410 | // Mark that this is a forced unwind, so _Unwind_Resume() can do | |
| 411 | // the right thing. | |
| 412 | exception_object->private_1 = (uintptr_t) stop; | |
| 413 | exception_object->private_2 = (uintptr_t) stop_parameter; | |
| 414 | ||
| 415 | // do it | |
| 416 | return unwind_phase2_forced(&uc, &cursor, exception_object, stop, stop_parameter); | |
| 417 | } | |
| 418 | ||
| 419 | ||
| 420 | /// Called by personality handler during phase 2 to get LSDA for current frame. | |
| 421 | _LIBUNWIND_EXPORT uintptr_t | |
| 422 | _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { | |
| 423 | unw_cursor_t *cursor = (unw_cursor_t *)context; | |
| 424 | unw_proc_info_t frameInfo; | |
| 425 | uintptr_t result = 0; | |
| 426 | if (unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) | |
| 427 | result = (uintptr_t)frameInfo.lsda; | |
| 428 | _LIBUNWIND_TRACE_API( | |
| 429 | "_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR, | |
| 430 | (void *)context, result); | |
| 431 | if (result != 0) { | |
| 432 | if (*((uint8_t *)result) != 0xFF) | |
| 433 | _LIBUNWIND_DEBUG_LOG("lsda at 0x%" PRIxPTR " does not start with 0xFF", | |
| 434 | result); | |
| 435 | } | |
| 436 | return result; | |
| 437 | } | |
| 438 | ||
| 439 | ||
| 440 | /// Called by personality handler during phase 2 to find the start of the | |
| 441 | /// function. | |
| 442 | _LIBUNWIND_EXPORT uintptr_t | |
| 443 | _Unwind_GetRegionStart(struct _Unwind_Context *context) { | |
| 444 | unw_cursor_t *cursor = (unw_cursor_t *)context; | |
| 445 | unw_proc_info_t frameInfo; | |
| 446 | uintptr_t result = 0; | |
| 447 | if (unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) | |
| 448 | result = (uintptr_t)frameInfo.start_ip; | |
| 449 | _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%" PRIxPTR, | |
| 450 | (void *)context, result); | |
| 451 | return result; | |
| 452 | } | |
| 453 | ||
| 454 | #endif // !_LIBUNWIND_SUPPORT_SEH_UNWIND | |
| 455 | ||
| 456 | /// Called by personality handler during phase 2 if a foreign exception | |
| 457 | // is caught. | |
| 458 | _LIBUNWIND_EXPORT void | |
| 459 | _Unwind_DeleteException(_Unwind_Exception *exception_object) { | |
| 460 | _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)", | |
| 461 | (void *)exception_object); | |
| 462 | if (exception_object->exception_cleanup != NULL) | |
| 463 | (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, | |
| 464 | exception_object); | |
| 465 | } | |
| 466 | ||
| 467 | /// Called by personality handler during phase 2 to get register values. | |
| 468 | _LIBUNWIND_EXPORT uintptr_t | |
| 469 | _Unwind_GetGR(struct _Unwind_Context *context, int index) { | |
| 470 | unw_cursor_t *cursor = (unw_cursor_t *)context; | |
| 471 | unw_word_t result; | |
| 472 | unw_get_reg(cursor, index, &result); | |
| 473 | _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%" PRIxPTR, | |
| 474 | (void *)context, index, result); | |
| 475 | return (uintptr_t)result; | |
| 476 | } | |
| 477 | ||
| 478 | /// Called by personality handler during phase 2 to alter register values. | |
| 479 | _LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index, | |
| 480 | uintptr_t value) { | |
| 481 | _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0" PRIxPTR | |
| 482 | ")", | |
| 483 | (void *)context, index, value); | |
| 484 | unw_cursor_t *cursor = (unw_cursor_t *)context; | |
| 485 | unw_set_reg(cursor, index, value); | |
| 486 | } | |
| 487 | ||
| 488 | /// Called by personality handler during phase 2 to get instruction pointer. | |
| 489 | _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) { | |
| 490 | unw_cursor_t *cursor = (unw_cursor_t *)context; | |
| 491 | unw_word_t result; | |
| 492 | unw_get_reg(cursor, UNW_REG_IP, &result); | |
| 493 | _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIxPTR, | |
| 494 | (void *)context, result); | |
| 495 | return (uintptr_t)result; | |
| 496 | } | |
| 497 | ||
| 498 | /// Called by personality handler during phase 2 to alter instruction pointer, | |
| 499 | /// such as setting where the landing pad is, so _Unwind_Resume() will | |
| 500 | /// start executing in the landing pad. | |
| 501 | _LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context, | |
| 502 | uintptr_t value) { | |
| 503 | _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0" PRIxPTR ")", | |
| 504 | (void *)context, value); | |
| 505 | unw_cursor_t *cursor = (unw_cursor_t *)context; | |
| 506 | unw_set_reg(cursor, UNW_REG_IP, value); | |
| 507 | } | |
| 508 | ||
| 509 | #endif // !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__) |
libunwind/src/UnwindRegistersRestore.S created+1030| ... | ... | @@ -0,0 +1,1030 @@ |
| 1 | //===-------------------- UnwindRegistersRestore.S ------------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is dual licensed under the MIT and the University of Illinois Open | |
| 6 | // Source Licenses. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | //===----------------------------------------------------------------------===// | |
| 9 | ||
| 10 | #include "assembly.h" | |
| 11 | ||
| 12 | .text | |
| 13 | ||
| 14 | #if !defined(__USING_SJLJ_EXCEPTIONS__) | |
| 15 | ||
| 16 | #if defined(__i386__) | |
| 17 | DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_x866jumptoEv) | |
| 18 | # | |
| 19 | # void libunwind::Registers_x86::jumpto() | |
| 20 | # | |
| 21 | #if defined(_WIN32) | |
| 22 | # On windows, the 'this' pointer is passed in ecx instead of on the stack | |
| 23 | movl %ecx, %eax | |
| 24 | #else | |
| 25 | # On entry: | |
| 26 | # + + | |
| 27 | # +-----------------------+ | |
| 28 | # + thread_state pointer + | |
| 29 | # +-----------------------+ | |
| 30 | # + return address + | |
| 31 | # +-----------------------+ <-- SP | |
| 32 | # + + | |
| 33 | movl 4(%esp), %eax | |
| 34 | #endif | |
| 35 | # set up eax and ret on new stack location | |
| 36 | movl 28(%eax), %edx # edx holds new stack pointer | |
| 37 | subl $8,%edx | |
| 38 | movl %edx, 28(%eax) | |
| 39 | movl 0(%eax), %ebx | |
| 40 | movl %ebx, 0(%edx) | |
| 41 | movl 40(%eax), %ebx | |
| 42 | movl %ebx, 4(%edx) | |
| 43 | # we now have ret and eax pushed onto where new stack will be | |
| 44 | # restore all registers | |
| 45 | movl 4(%eax), %ebx | |
| 46 | movl 8(%eax), %ecx | |
| 47 | movl 12(%eax), %edx | |
| 48 | movl 16(%eax), %edi | |
| 49 | movl 20(%eax), %esi | |
| 50 | movl 24(%eax), %ebp | |
| 51 | movl 28(%eax), %esp | |
| 52 | # skip ss | |
| 53 | # skip eflags | |
| 54 | pop %eax # eax was already pushed on new stack | |
| 55 | ret # eip was already pushed on new stack | |
| 56 | # skip cs | |
| 57 | # skip ds | |
| 58 | # skip es | |
| 59 | # skip fs | |
| 60 | # skip gs | |
| 61 | ||
| 62 | #elif defined(__x86_64__) | |
| 63 | ||
| 64 | DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind16Registers_x86_646jumptoEv) | |
| 65 | # | |
| 66 | # void libunwind::Registers_x86_64::jumpto() | |
| 67 | # | |
| 68 | #if defined(_WIN64) | |
| 69 | # On entry, thread_state pointer is in rcx; move it into rdi | |
| 70 | # to share restore code below. Since this routine restores and | |
| 71 | # overwrites all registers, we can use the same registers for | |
| 72 | # pointers and temporaries as on unix even though win64 normally | |
| 73 | # mustn't clobber some of them. | |
| 74 | movq %rcx, %rdi | |
| 75 | #else | |
| 76 | # On entry, thread_state pointer is in rdi | |
| 77 | #endif | |
| 78 | ||
| 79 | movq 56(%rdi), %rax # rax holds new stack pointer | |
| 80 | subq $16, %rax | |
| 81 | movq %rax, 56(%rdi) | |
| 82 | movq 32(%rdi), %rbx # store new rdi on new stack | |
| 83 | movq %rbx, 0(%rax) | |
| 84 | movq 128(%rdi), %rbx # store new rip on new stack | |
| 85 | movq %rbx, 8(%rax) | |
| 86 | # restore all registers | |
| 87 | movq 0(%rdi), %rax | |
| 88 | movq 8(%rdi), %rbx | |
| 89 | movq 16(%rdi), %rcx | |
| 90 | movq 24(%rdi), %rdx | |
| 91 | # restore rdi later | |
| 92 | movq 40(%rdi), %rsi | |
| 93 | movq 48(%rdi), %rbp | |
| 94 | # restore rsp later | |
| 95 | movq 64(%rdi), %r8 | |
| 96 | movq 72(%rdi), %r9 | |
| 97 | movq 80(%rdi), %r10 | |
| 98 | movq 88(%rdi), %r11 | |
| 99 | movq 96(%rdi), %r12 | |
| 100 | movq 104(%rdi), %r13 | |
| 101 | movq 112(%rdi), %r14 | |
| 102 | movq 120(%rdi), %r15 | |
| 103 | # skip rflags | |
| 104 | # skip cs | |
| 105 | # skip fs | |
| 106 | # skip gs | |
| 107 | ||
| 108 | #if defined(_WIN64) | |
| 109 | movdqu 176(%rdi),%xmm0 | |
| 110 | movdqu 192(%rdi),%xmm1 | |
| 111 | movdqu 208(%rdi),%xmm2 | |
| 112 | movdqu 224(%rdi),%xmm3 | |
| 113 | movdqu 240(%rdi),%xmm4 | |
| 114 | movdqu 256(%rdi),%xmm5 | |
| 115 | movdqu 272(%rdi),%xmm6 | |
| 116 | movdqu 288(%rdi),%xmm7 | |
| 117 | movdqu 304(%rdi),%xmm8 | |
| 118 | movdqu 320(%rdi),%xmm9 | |
| 119 | movdqu 336(%rdi),%xmm10 | |
| 120 | movdqu 352(%rdi),%xmm11 | |
| 121 | movdqu 368(%rdi),%xmm12 | |
| 122 | movdqu 384(%rdi),%xmm13 | |
| 123 | movdqu 400(%rdi),%xmm14 | |
| 124 | movdqu 416(%rdi),%xmm15 | |
| 125 | #endif | |
| 126 | movq 56(%rdi), %rsp # cut back rsp to new location | |
| 127 | pop %rdi # rdi was saved here earlier | |
| 128 | ret # rip was saved here | |
| 129 | ||
| 130 | ||
| 131 | #elif defined(__powerpc64__) | |
| 132 | ||
| 133 | DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind15Registers_ppc646jumptoEv) | |
| 134 | // | |
| 135 | // void libunwind::Registers_ppc64::jumpto() | |
| 136 | // | |
| 137 | // On entry: | |
| 138 | // thread_state pointer is in r3 | |
| 139 | // | |
| 140 | ||
| 141 | // load register (GPR) | |
| 142 | #define PPC64_LR(n) \ | |
| 143 | ld %r##n, (8 * (n + 2))(%r3) | |
| 144 | ||
| 145 | // restore integral registers | |
| 146 | // skip r0 for now | |
| 147 | // skip r1 for now | |
| 148 | PPC64_LR(2) | |
| 149 | // skip r3 for now | |
| 150 | // skip r4 for now | |
| 151 | // skip r5 for now | |
| 152 | PPC64_LR(6) | |
| 153 | PPC64_LR(7) | |
| 154 | PPC64_LR(8) | |
| 155 | PPC64_LR(9) | |
| 156 | PPC64_LR(10) | |
| 157 | PPC64_LR(11) | |
| 158 | PPC64_LR(12) | |
| 159 | PPC64_LR(13) | |
| 160 | PPC64_LR(14) | |
| 161 | PPC64_LR(15) | |
| 162 | PPC64_LR(16) | |
| 163 | PPC64_LR(17) | |
| 164 | PPC64_LR(18) | |
| 165 | PPC64_LR(19) | |
| 166 | PPC64_LR(20) | |
| 167 | PPC64_LR(21) | |
| 168 | PPC64_LR(22) | |
| 169 | PPC64_LR(23) | |
| 170 | PPC64_LR(24) | |
| 171 | PPC64_LR(25) | |
| 172 | PPC64_LR(26) | |
| 173 | PPC64_LR(27) | |
| 174 | PPC64_LR(28) | |
| 175 | PPC64_LR(29) | |
| 176 | PPC64_LR(30) | |
| 177 | PPC64_LR(31) | |
| 178 | ||
| 179 | #ifdef PPC64_HAS_VMX | |
| 180 | ||
| 181 | // restore VS registers | |
| 182 | // (note that this also restores floating point registers and V registers, | |
| 183 | // because part of VS is mapped to these registers) | |
| 184 | ||
| 185 | addi %r4, %r3, PPC64_OFFS_FP | |
| 186 | ||
| 187 | // load VS register | |
| 188 | #define PPC64_LVS(n) \ | |
| 189 | lxvd2x %vs##n, 0, %r4 ;\ | |
| 190 | addi %r4, %r4, 16 | |
| 191 | ||
| 192 | // restore the first 32 VS regs (and also all floating point regs) | |
| 193 | PPC64_LVS(0) | |
| 194 | PPC64_LVS(1) | |
| 195 | PPC64_LVS(2) | |
| 196 | PPC64_LVS(3) | |
| 197 | PPC64_LVS(4) | |
| 198 | PPC64_LVS(5) | |
| 199 | PPC64_LVS(6) | |
| 200 | PPC64_LVS(7) | |
| 201 | PPC64_LVS(8) | |
| 202 | PPC64_LVS(9) | |
| 203 | PPC64_LVS(10) | |
| 204 | PPC64_LVS(11) | |
| 205 | PPC64_LVS(12) | |
| 206 | PPC64_LVS(13) | |
| 207 | PPC64_LVS(14) | |
| 208 | PPC64_LVS(15) | |
| 209 | PPC64_LVS(16) | |
| 210 | PPC64_LVS(17) | |
| 211 | PPC64_LVS(18) | |
| 212 | PPC64_LVS(19) | |
| 213 | PPC64_LVS(20) | |
| 214 | PPC64_LVS(21) | |
| 215 | PPC64_LVS(22) | |
| 216 | PPC64_LVS(23) | |
| 217 | PPC64_LVS(24) | |
| 218 | PPC64_LVS(25) | |
| 219 | PPC64_LVS(26) | |
| 220 | PPC64_LVS(27) | |
| 221 | PPC64_LVS(28) | |
| 222 | PPC64_LVS(29) | |
| 223 | PPC64_LVS(30) | |
| 224 | PPC64_LVS(31) | |
| 225 | ||
| 226 | // use VRSAVE to conditionally restore the remaining VS regs, | |
| 227 | // that are where the V regs are mapped | |
| 228 | ||
| 229 | ld %r5, PPC64_OFFS_VRSAVE(%r3) // test VRsave | |
| 230 | cmpwi %r5, 0 | |
| 231 | beq Lnovec | |
| 232 | ||
| 233 | // conditionally load VS | |
| 234 | #define PPC64_CLVS_BOTTOM(n) \ | |
| 235 | beq Ldone##n ;\ | |
| 236 | addi %r4, %r3, PPC64_OFFS_FP + n * 16 ;\ | |
| 237 | lxvd2x %vs##n, 0, %r4 ;\ | |
| 238 | Ldone##n: | |
| 239 | ||
| 240 | #define PPC64_CLVSl(n) \ | |
| 241 | andis. %r0, %r5, (1<<(47-n)) ;\ | |
| 242 | PPC64_CLVS_BOTTOM(n) | |
| 243 | ||
| 244 | #define PPC64_CLVSh(n) \ | |
| 245 | andi. %r0, %r5, (1<<(63-n)) ;\ | |
| 246 | PPC64_CLVS_BOTTOM(n) | |
| 247 | ||
| 248 | PPC64_CLVSl(32) | |
| 249 | PPC64_CLVSl(33) | |
| 250 | PPC64_CLVSl(34) | |
| 251 | PPC64_CLVSl(35) | |
| 252 | PPC64_CLVSl(36) | |
| 253 | PPC64_CLVSl(37) | |
| 254 | PPC64_CLVSl(38) | |
| 255 | PPC64_CLVSl(39) | |
| 256 | PPC64_CLVSl(40) | |
| 257 | PPC64_CLVSl(41) | |
| 258 | PPC64_CLVSl(42) | |
| 259 | PPC64_CLVSl(43) | |
| 260 | PPC64_CLVSl(44) | |
| 261 | PPC64_CLVSl(45) | |
| 262 | PPC64_CLVSl(46) | |
| 263 | PPC64_CLVSl(47) | |
| 264 | PPC64_CLVSh(48) | |
| 265 | PPC64_CLVSh(49) | |
| 266 | PPC64_CLVSh(50) | |
| 267 | PPC64_CLVSh(51) | |
| 268 | PPC64_CLVSh(52) | |
| 269 | PPC64_CLVSh(53) | |
| 270 | PPC64_CLVSh(54) | |
| 271 | PPC64_CLVSh(55) | |
| 272 | PPC64_CLVSh(56) | |
| 273 | PPC64_CLVSh(57) | |
| 274 | PPC64_CLVSh(58) | |
| 275 | PPC64_CLVSh(59) | |
| 276 | PPC64_CLVSh(60) | |
| 277 | PPC64_CLVSh(61) | |
| 278 | PPC64_CLVSh(62) | |
| 279 | PPC64_CLVSh(63) | |
| 280 | ||
| 281 | #else | |
| 282 | ||
| 283 | // load FP register | |
| 284 | #define PPC64_LF(n) \ | |
| 285 | lfd %f##n, (PPC64_OFFS_FP + n * 16)(%r3) | |
| 286 | ||
| 287 | // restore float registers | |
| 288 | PPC64_LF(0) | |
| 289 | PPC64_LF(1) | |
| 290 | PPC64_LF(2) | |
| 291 | PPC64_LF(3) | |
| 292 | PPC64_LF(4) | |
| 293 | PPC64_LF(5) | |
| 294 | PPC64_LF(6) | |
| 295 | PPC64_LF(7) | |
| 296 | PPC64_LF(8) | |
| 297 | PPC64_LF(9) | |
| 298 | PPC64_LF(10) | |
| 299 | PPC64_LF(11) | |
| 300 | PPC64_LF(12) | |
| 301 | PPC64_LF(13) | |
| 302 | PPC64_LF(14) | |
| 303 | PPC64_LF(15) | |
| 304 | PPC64_LF(16) | |
| 305 | PPC64_LF(17) | |
| 306 | PPC64_LF(18) | |
| 307 | PPC64_LF(19) | |
| 308 | PPC64_LF(20) | |
| 309 | PPC64_LF(21) | |
| 310 | PPC64_LF(22) | |
| 311 | PPC64_LF(23) | |
| 312 | PPC64_LF(24) | |
| 313 | PPC64_LF(25) | |
| 314 | PPC64_LF(26) | |
| 315 | PPC64_LF(27) | |
| 316 | PPC64_LF(28) | |
| 317 | PPC64_LF(29) | |
| 318 | PPC64_LF(30) | |
| 319 | PPC64_LF(31) | |
| 320 | ||
| 321 | // restore vector registers if any are in use | |
| 322 | ld %r5, PPC64_OFFS_VRSAVE(%r3) // test VRsave | |
| 323 | cmpwi %r5, 0 | |
| 324 | beq Lnovec | |
| 325 | ||
| 326 | subi %r4, %r1, 16 | |
| 327 | // r4 is now a 16-byte aligned pointer into the red zone | |
| 328 | // the _vectorScalarRegisters may not be 16-byte aligned | |
| 329 | // so copy via red zone temp buffer | |
| 330 | ||
| 331 | #define PPC64_CLV_UNALIGNED_BOTTOM(n) \ | |
| 332 | beq Ldone##n ;\ | |
| 333 | ld %r0, (PPC64_OFFS_V + n * 16)(%r3) ;\ | |
| 334 | std %r0, 0(%r4) ;\ | |
| 335 | ld %r0, (PPC64_OFFS_V + n * 16 + 8)(%r3) ;\ | |
| 336 | std %r0, 8(%r4) ;\ | |
| 337 | lvx %v##n, 0, %r4 ;\ | |
| 338 | Ldone ## n: | |
| 339 | ||
| 340 | #define PPC64_CLV_UNALIGNEDl(n) \ | |
| 341 | andis. %r0, %r5, (1<<(15-n)) ;\ | |
| 342 | PPC64_CLV_UNALIGNED_BOTTOM(n) | |
| 343 | ||
| 344 | #define PPC64_CLV_UNALIGNEDh(n) \ | |
| 345 | andi. %r0, %r5, (1<<(31-n)) ;\ | |
| 346 | PPC64_CLV_UNALIGNED_BOTTOM(n) | |
| 347 | ||
| 348 | PPC64_CLV_UNALIGNEDl(0) | |
| 349 | PPC64_CLV_UNALIGNEDl(1) | |
| 350 | PPC64_CLV_UNALIGNEDl(2) | |
| 351 | PPC64_CLV_UNALIGNEDl(3) | |
| 352 | PPC64_CLV_UNALIGNEDl(4) | |
| 353 | PPC64_CLV_UNALIGNEDl(5) | |
| 354 | PPC64_CLV_UNALIGNEDl(6) | |
| 355 | PPC64_CLV_UNALIGNEDl(7) | |
| 356 | PPC64_CLV_UNALIGNEDl(8) | |
| 357 | PPC64_CLV_UNALIGNEDl(9) | |
| 358 | PPC64_CLV_UNALIGNEDl(10) | |
| 359 | PPC64_CLV_UNALIGNEDl(11) | |
| 360 | PPC64_CLV_UNALIGNEDl(12) | |
| 361 | PPC64_CLV_UNALIGNEDl(13) | |
| 362 | PPC64_CLV_UNALIGNEDl(14) | |
| 363 | PPC64_CLV_UNALIGNEDl(15) | |
| 364 | PPC64_CLV_UNALIGNEDh(16) | |
| 365 | PPC64_CLV_UNALIGNEDh(17) | |
| 366 | PPC64_CLV_UNALIGNEDh(18) | |
| 367 | PPC64_CLV_UNALIGNEDh(19) | |
| 368 | PPC64_CLV_UNALIGNEDh(20) | |
| 369 | PPC64_CLV_UNALIGNEDh(21) | |
| 370 | PPC64_CLV_UNALIGNEDh(22) | |
| 371 | PPC64_CLV_UNALIGNEDh(23) | |
| 372 | PPC64_CLV_UNALIGNEDh(24) | |
| 373 | PPC64_CLV_UNALIGNEDh(25) | |
| 374 | PPC64_CLV_UNALIGNEDh(26) | |
| 375 | PPC64_CLV_UNALIGNEDh(27) | |
| 376 | PPC64_CLV_UNALIGNEDh(28) | |
| 377 | PPC64_CLV_UNALIGNEDh(29) | |
| 378 | PPC64_CLV_UNALIGNEDh(30) | |
| 379 | PPC64_CLV_UNALIGNEDh(31) | |
| 380 | ||
| 381 | #endif | |
| 382 | ||
| 383 | Lnovec: | |
| 384 | ld %r0, PPC64_OFFS_CR(%r3) | |
| 385 | mtcr %r0 | |
| 386 | ld %r0, PPC64_OFFS_SRR0(%r3) | |
| 387 | mtctr %r0 | |
| 388 | ||
| 389 | PPC64_LR(0) | |
| 390 | PPC64_LR(5) | |
| 391 | PPC64_LR(4) | |
| 392 | PPC64_LR(1) | |
| 393 | PPC64_LR(3) | |
| 394 | bctr | |
| 395 | ||
| 396 | #elif defined(__ppc__) | |
| 397 | ||
| 398 | DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv) | |
| 399 | ; | |
| 400 | ; void libunwind::Registers_ppc::jumpto() | |
| 401 | ; | |
| 402 | ; On entry: | |
| 403 | ; thread_state pointer is in r3 | |
| 404 | ; | |
| 405 | ||
| 406 | ; restore integral registerrs | |
| 407 | ; skip r0 for now | |
| 408 | ; skip r1 for now | |
| 409 | lwz r2, 16(r3) | |
| 410 | ; skip r3 for now | |
| 411 | ; skip r4 for now | |
| 412 | ; skip r5 for now | |
| 413 | lwz r6, 32(r3) | |
| 414 | lwz r7, 36(r3) | |
| 415 | lwz r8, 40(r3) | |
| 416 | lwz r9, 44(r3) | |
| 417 | lwz r10, 48(r3) | |
| 418 | lwz r11, 52(r3) | |
| 419 | lwz r12, 56(r3) | |
| 420 | lwz r13, 60(r3) | |
| 421 | lwz r14, 64(r3) | |
| 422 | lwz r15, 68(r3) | |
| 423 | lwz r16, 72(r3) | |
| 424 | lwz r17, 76(r3) | |
| 425 | lwz r18, 80(r3) | |
| 426 | lwz r19, 84(r3) | |
| 427 | lwz r20, 88(r3) | |
| 428 | lwz r21, 92(r3) | |
| 429 | lwz r22, 96(r3) | |
| 430 | lwz r23,100(r3) | |
| 431 | lwz r24,104(r3) | |
| 432 | lwz r25,108(r3) | |
| 433 | lwz r26,112(r3) | |
| 434 | lwz r27,116(r3) | |
| 435 | lwz r28,120(r3) | |
| 436 | lwz r29,124(r3) | |
| 437 | lwz r30,128(r3) | |
| 438 | lwz r31,132(r3) | |
| 439 | ||
| 440 | ; restore float registers | |
| 441 | lfd f0, 160(r3) | |
| 442 | lfd f1, 168(r3) | |
| 443 | lfd f2, 176(r3) | |
| 444 | lfd f3, 184(r3) | |
| 445 | lfd f4, 192(r3) | |
| 446 | lfd f5, 200(r3) | |
| 447 | lfd f6, 208(r3) | |
| 448 | lfd f7, 216(r3) | |
| 449 | lfd f8, 224(r3) | |
| 450 | lfd f9, 232(r3) | |
| 451 | lfd f10,240(r3) | |
| 452 | lfd f11,248(r3) | |
| 453 | lfd f12,256(r3) | |
| 454 | lfd f13,264(r3) | |
| 455 | lfd f14,272(r3) | |
| 456 | lfd f15,280(r3) | |
| 457 | lfd f16,288(r3) | |
| 458 | lfd f17,296(r3) | |
| 459 | lfd f18,304(r3) | |
| 460 | lfd f19,312(r3) | |
| 461 | lfd f20,320(r3) | |
| 462 | lfd f21,328(r3) | |
| 463 | lfd f22,336(r3) | |
| 464 | lfd f23,344(r3) | |
| 465 | lfd f24,352(r3) | |
| 466 | lfd f25,360(r3) | |
| 467 | lfd f26,368(r3) | |
| 468 | lfd f27,376(r3) | |
| 469 | lfd f28,384(r3) | |
| 470 | lfd f29,392(r3) | |
| 471 | lfd f30,400(r3) | |
| 472 | lfd f31,408(r3) | |
| 473 | ||
| 474 | ; restore vector registers if any are in use | |
| 475 | lwz r5,156(r3) ; test VRsave | |
| 476 | cmpwi r5,0 | |
| 477 | beq Lnovec | |
| 478 | ||
| 479 | subi r4,r1,16 | |
| 480 | rlwinm r4,r4,0,0,27 ; mask low 4-bits | |
| 481 | ; r4 is now a 16-byte aligned pointer into the red zone | |
| 482 | ; the _vectorRegisters may not be 16-byte aligned so copy via red zone temp buffer | |
| 483 | ||
| 484 | ||
| 485 | #define LOAD_VECTOR_UNALIGNEDl(_index) \ | |
| 486 | andis. r0,r5,(1<<(15-_index)) @\ | |
| 487 | beq Ldone ## _index @\ | |
| 488 | lwz r0, 424+_index*16(r3) @\ | |
| 489 | stw r0, 0(r4) @\ | |
| 490 | lwz r0, 424+_index*16+4(r3) @\ | |
| 491 | stw r0, 4(r4) @\ | |
| 492 | lwz r0, 424+_index*16+8(r3) @\ | |
| 493 | stw r0, 8(r4) @\ | |
| 494 | lwz r0, 424+_index*16+12(r3)@\ | |
| 495 | stw r0, 12(r4) @\ | |
| 496 | lvx v ## _index,0,r4 @\ | |
| 497 | Ldone ## _index: | |
| 498 | ||
| 499 | #define LOAD_VECTOR_UNALIGNEDh(_index) \ | |
| 500 | andi. r0,r5,(1<<(31-_index)) @\ | |
| 501 | beq Ldone ## _index @\ | |
| 502 | lwz r0, 424+_index*16(r3) @\ | |
| 503 | stw r0, 0(r4) @\ | |
| 504 | lwz r0, 424+_index*16+4(r3) @\ | |
| 505 | stw r0, 4(r4) @\ | |
| 506 | lwz r0, 424+_index*16+8(r3) @\ | |
| 507 | stw r0, 8(r4) @\ | |
| 508 | lwz r0, 424+_index*16+12(r3)@\ | |
| 509 | stw r0, 12(r4) @\ | |
| 510 | lvx v ## _index,0,r4 @\ | |
| 511 | Ldone ## _index: | |
| 512 | ||
| 513 | ||
| 514 | LOAD_VECTOR_UNALIGNEDl(0) | |
| 515 | LOAD_VECTOR_UNALIGNEDl(1) | |
| 516 | LOAD_VECTOR_UNALIGNEDl(2) | |
| 517 | LOAD_VECTOR_UNALIGNEDl(3) | |
| 518 | LOAD_VECTOR_UNALIGNEDl(4) | |
| 519 | LOAD_VECTOR_UNALIGNEDl(5) | |
| 520 | LOAD_VECTOR_UNALIGNEDl(6) | |
| 521 | LOAD_VECTOR_UNALIGNEDl(7) | |
| 522 | LOAD_VECTOR_UNALIGNEDl(8) | |
| 523 | LOAD_VECTOR_UNALIGNEDl(9) | |
| 524 | LOAD_VECTOR_UNALIGNEDl(10) | |
| 525 | LOAD_VECTOR_UNALIGNEDl(11) | |
| 526 | LOAD_VECTOR_UNALIGNEDl(12) | |
| 527 | LOAD_VECTOR_UNALIGNEDl(13) | |
| 528 | LOAD_VECTOR_UNALIGNEDl(14) | |
| 529 | LOAD_VECTOR_UNALIGNEDl(15) | |
| 530 | LOAD_VECTOR_UNALIGNEDh(16) | |
| 531 | LOAD_VECTOR_UNALIGNEDh(17) | |
| 532 | LOAD_VECTOR_UNALIGNEDh(18) | |
| 533 | LOAD_VECTOR_UNALIGNEDh(19) | |
| 534 | LOAD_VECTOR_UNALIGNEDh(20) | |
| 535 | LOAD_VECTOR_UNALIGNEDh(21) | |
| 536 | LOAD_VECTOR_UNALIGNEDh(22) | |
| 537 | LOAD_VECTOR_UNALIGNEDh(23) | |
| 538 | LOAD_VECTOR_UNALIGNEDh(24) | |
| 539 | LOAD_VECTOR_UNALIGNEDh(25) | |
| 540 | LOAD_VECTOR_UNALIGNEDh(26) | |
| 541 | LOAD_VECTOR_UNALIGNEDh(27) | |
| 542 | LOAD_VECTOR_UNALIGNEDh(28) | |
| 543 | LOAD_VECTOR_UNALIGNEDh(29) | |
| 544 | LOAD_VECTOR_UNALIGNEDh(30) | |
| 545 | LOAD_VECTOR_UNALIGNEDh(31) | |
| 546 | ||
| 547 | Lnovec: | |
| 548 | lwz r0, 136(r3) ; __cr | |
| 549 | mtocrf 255,r0 | |
| 550 | lwz r0, 148(r3) ; __ctr | |
| 551 | mtctr r0 | |
| 552 | lwz r0, 0(r3) ; __ssr0 | |
| 553 | mtctr r0 | |
| 554 | lwz r0, 8(r3) ; do r0 now | |
| 555 | lwz r5,28(r3) ; do r5 now | |
| 556 | lwz r4,24(r3) ; do r4 now | |
| 557 | lwz r1,12(r3) ; do sp now | |
| 558 | lwz r3,20(r3) ; do r3 last | |
| 559 | bctr | |
| 560 | ||
| 561 | #elif defined(__arm64__) || defined(__aarch64__) | |
| 562 | ||
| 563 | // | |
| 564 | // void libunwind::Registers_arm64::jumpto() | |
| 565 | // | |
| 566 | // On entry: | |
| 567 | // thread_state pointer is in x0 | |
| 568 | // | |
| 569 | .p2align 2 | |
| 570 | DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind15Registers_arm646jumptoEv) | |
| 571 | // skip restore of x0,x1 for now | |
| 572 | ldp x2, x3, [x0, #0x010] | |
| 573 | ldp x4, x5, [x0, #0x020] | |
| 574 | ldp x6, x7, [x0, #0x030] | |
| 575 | ldp x8, x9, [x0, #0x040] | |
| 576 | ldp x10,x11, [x0, #0x050] | |
| 577 | ldp x12,x13, [x0, #0x060] | |
| 578 | ldp x14,x15, [x0, #0x070] | |
| 579 | ldp x16,x17, [x0, #0x080] | |
| 580 | ldp x18,x19, [x0, #0x090] | |
| 581 | ldp x20,x21, [x0, #0x0A0] | |
| 582 | ldp x22,x23, [x0, #0x0B0] | |
| 583 | ldp x24,x25, [x0, #0x0C0] | |
| 584 | ldp x26,x27, [x0, #0x0D0] | |
| 585 | ldp x28,x29, [x0, #0x0E0] | |
| 586 | ldr x30, [x0, #0x100] // restore pc into lr | |
| 587 | ldr x1, [x0, #0x0F8] | |
| 588 | mov sp,x1 // restore sp | |
| 589 | ||
| 590 | ldp d0, d1, [x0, #0x110] | |
| 591 | ldp d2, d3, [x0, #0x120] | |
| 592 | ldp d4, d5, [x0, #0x130] | |
| 593 | ldp d6, d7, [x0, #0x140] | |
| 594 | ldp d8, d9, [x0, #0x150] | |
| 595 | ldp d10,d11, [x0, #0x160] | |
| 596 | ldp d12,d13, [x0, #0x170] | |
| 597 | ldp d14,d15, [x0, #0x180] | |
| 598 | ldp d16,d17, [x0, #0x190] | |
| 599 | ldp d18,d19, [x0, #0x1A0] | |
| 600 | ldp d20,d21, [x0, #0x1B0] | |
| 601 | ldp d22,d23, [x0, #0x1C0] | |
| 602 | ldp d24,d25, [x0, #0x1D0] | |
| 603 | ldp d26,d27, [x0, #0x1E0] | |
| 604 | ldp d28,d29, [x0, #0x1F0] | |
| 605 | ldr d30, [x0, #0x200] | |
| 606 | ldr d31, [x0, #0x208] | |
| 607 | ||
| 608 | ldp x0, x1, [x0, #0x000] // restore x0,x1 | |
| 609 | ret x30 // jump to pc | |
| 610 | ||
| 611 | #elif defined(__arm__) && !defined(__APPLE__) | |
| 612 | ||
| 613 | #if !defined(__ARM_ARCH_ISA_ARM) | |
| 614 | .thumb | |
| 615 | #endif | |
| 616 | ||
| 617 | @ | |
| 618 | @ void libunwind::Registers_arm::restoreCoreAndJumpTo() | |
| 619 | @ | |
| 620 | @ On entry: | |
| 621 | @ thread_state pointer is in r0 | |
| 622 | @ | |
| 623 | .p2align 2 | |
| 624 | DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm20restoreCoreAndJumpToEv) | |
| 625 | #if !defined(__ARM_ARCH_ISA_ARM) && __ARM_ARCH_ISA_THUMB == 1 | |
| 626 | @ r8-r11: ldm into r1-r4, then mov to r8-r11 | |
| 627 | adds r0, #0x20 | |
| 628 | ldm r0!, {r1-r4} | |
| 629 | subs r0, #0x30 | |
| 630 | mov r8, r1 | |
| 631 | mov r9, r2 | |
| 632 | mov r10, r3 | |
| 633 | mov r11, r4 | |
| 634 | @ r12 does not need loading, it it the intra-procedure-call scratch register | |
| 635 | ldr r2, [r0, #0x34] | |
| 636 | ldr r3, [r0, #0x3c] | |
| 637 | mov sp, r2 | |
| 638 | mov lr, r3 @ restore pc into lr | |
| 639 | ldm r0, {r0-r7} | |
| 640 | #else | |
| 641 | @ Use lr as base so that r0 can be restored. | |
| 642 | mov lr, r0 | |
| 643 | @ 32bit thumb-2 restrictions for ldm: | |
| 644 | @ . the sp (r13) cannot be in the list | |
| 645 | @ . the pc (r15) and lr (r14) cannot both be in the list in an LDM instruction | |
| 646 | ldm lr, {r0-r12} | |
| 647 | ldr sp, [lr, #52] | |
| 648 | ldr lr, [lr, #60] @ restore pc into lr | |
| 649 | #endif | |
| 650 | JMP(lr) | |
| 651 | ||
| 652 | @ | |
| 653 | @ static void libunwind::Registers_arm::restoreVFPWithFLDMD(unw_fpreg_t* values) | |
| 654 | @ | |
| 655 | @ On entry: | |
| 656 | @ values pointer is in r0 | |
| 657 | @ | |
| 658 | .p2align 2 | |
| 659 | #if defined(__ELF__) | |
| 660 | .fpu vfpv3-d16 | |
| 661 | #endif | |
| 662 | DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMDEPy) | |
| 663 | @ VFP and iwMMX instructions are only available when compiling with the flags | |
| 664 | @ that enable them. We do not want to do that in the library (because we do not | |
| 665 | @ want the compiler to generate instructions that access those) but this is | |
| 666 | @ only accessed if the personality routine needs these registers. Use of | |
| 667 | @ these registers implies they are, actually, available on the target, so | |
| 668 | @ it's ok to execute. | |
| 669 | @ So, generate the instruction using the corresponding coprocessor mnemonic. | |
| 670 | vldmia r0, {d0-d15} | |
| 671 | JMP(lr) | |
| 672 | ||
| 673 | @ | |
| 674 | @ static void libunwind::Registers_arm::restoreVFPWithFLDMX(unw_fpreg_t* values) | |
| 675 | @ | |
| 676 | @ On entry: | |
| 677 | @ values pointer is in r0 | |
| 678 | @ | |
| 679 | .p2align 2 | |
| 680 | #if defined(__ELF__) | |
| 681 | .fpu vfpv3-d16 | |
| 682 | #endif | |
| 683 | DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMXEPy) | |
| 684 | vldmia r0, {d0-d15} @ fldmiax is deprecated in ARMv7+ and now behaves like vldmia | |
| 685 | JMP(lr) | |
| 686 | ||
| 687 | @ | |
| 688 | @ static void libunwind::Registers_arm::restoreVFPv3(unw_fpreg_t* values) | |
| 689 | @ | |
| 690 | @ On entry: | |
| 691 | @ values pointer is in r0 | |
| 692 | @ | |
| 693 | .p2align 2 | |
| 694 | #if defined(__ELF__) | |
| 695 | .fpu vfpv3 | |
| 696 | #endif | |
| 697 | DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreVFPv3EPy) | |
| 698 | vldmia r0, {d16-d31} | |
| 699 | JMP(lr) | |
| 700 | ||
| 701 | #if defined(__ARM_WMMX) | |
| 702 | ||
| 703 | @ | |
| 704 | @ static void libunwind::Registers_arm::restoreiWMMX(unw_fpreg_t* values) | |
| 705 | @ | |
| 706 | @ On entry: | |
| 707 | @ values pointer is in r0 | |
| 708 | @ | |
| 709 | .p2align 2 | |
| 710 | #if defined(__ELF__) | |
| 711 | .arch armv5te | |
| 712 | #endif | |
| 713 | DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreiWMMXEPy) | |
| 714 | ldcl p1, cr0, [r0], #8 @ wldrd wR0, [r0], #8 | |
| 715 | ldcl p1, cr1, [r0], #8 @ wldrd wR1, [r0], #8 | |
| 716 | ldcl p1, cr2, [r0], #8 @ wldrd wR2, [r0], #8 | |
| 717 | ldcl p1, cr3, [r0], #8 @ wldrd wR3, [r0], #8 | |
| 718 | ldcl p1, cr4, [r0], #8 @ wldrd wR4, [r0], #8 | |
| 719 | ldcl p1, cr5, [r0], #8 @ wldrd wR5, [r0], #8 | |
| 720 | ldcl p1, cr6, [r0], #8 @ wldrd wR6, [r0], #8 | |
| 721 | ldcl p1, cr7, [r0], #8 @ wldrd wR7, [r0], #8 | |
| 722 | ldcl p1, cr8, [r0], #8 @ wldrd wR8, [r0], #8 | |
| 723 | ldcl p1, cr9, [r0], #8 @ wldrd wR9, [r0], #8 | |
| 724 | ldcl p1, cr10, [r0], #8 @ wldrd wR10, [r0], #8 | |
| 725 | ldcl p1, cr11, [r0], #8 @ wldrd wR11, [r0], #8 | |
| 726 | ldcl p1, cr12, [r0], #8 @ wldrd wR12, [r0], #8 | |
| 727 | ldcl p1, cr13, [r0], #8 @ wldrd wR13, [r0], #8 | |
| 728 | ldcl p1, cr14, [r0], #8 @ wldrd wR14, [r0], #8 | |
| 729 | ldcl p1, cr15, [r0], #8 @ wldrd wR15, [r0], #8 | |
| 730 | JMP(lr) | |
| 731 | ||
| 732 | @ | |
| 733 | @ static void libunwind::Registers_arm::restoreiWMMXControl(unw_uint32_t* values) | |
| 734 | @ | |
| 735 | @ On entry: | |
| 736 | @ values pointer is in r0 | |
| 737 | @ | |
| 738 | .p2align 2 | |
| 739 | #if defined(__ELF__) | |
| 740 | .arch armv5te | |
| 741 | #endif | |
| 742 | DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreiWMMXControlEPj) | |
| 743 | ldc2 p1, cr8, [r0], #4 @ wldrw wCGR0, [r0], #4 | |
| 744 | ldc2 p1, cr9, [r0], #4 @ wldrw wCGR1, [r0], #4 | |
| 745 | ldc2 p1, cr10, [r0], #4 @ wldrw wCGR2, [r0], #4 | |
| 746 | ldc2 p1, cr11, [r0], #4 @ wldrw wCGR3, [r0], #4 | |
| 747 | JMP(lr) | |
| 748 | ||
| 749 | #endif | |
| 750 | ||
| 751 | #elif defined(__or1k__) | |
| 752 | ||
| 753 | DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv) | |
| 754 | # | |
| 755 | # void libunwind::Registers_or1k::jumpto() | |
| 756 | # | |
| 757 | # On entry: | |
| 758 | # thread_state pointer is in r3 | |
| 759 | # | |
| 760 | ||
| 761 | # restore integral registers | |
| 762 | l.lwz r0, 0(r3) | |
| 763 | l.lwz r1, 4(r3) | |
| 764 | l.lwz r2, 8(r3) | |
| 765 | # skip r3 for now | |
| 766 | l.lwz r4, 16(r3) | |
| 767 | l.lwz r5, 20(r3) | |
| 768 | l.lwz r6, 24(r3) | |
| 769 | l.lwz r7, 28(r3) | |
| 770 | l.lwz r8, 32(r3) | |
| 771 | # skip r9 | |
| 772 | l.lwz r10, 40(r3) | |
| 773 | l.lwz r11, 44(r3) | |
| 774 | l.lwz r12, 48(r3) | |
| 775 | l.lwz r13, 52(r3) | |
| 776 | l.lwz r14, 56(r3) | |
| 777 | l.lwz r15, 60(r3) | |
| 778 | l.lwz r16, 64(r3) | |
| 779 | l.lwz r17, 68(r3) | |
| 780 | l.lwz r18, 72(r3) | |
| 781 | l.lwz r19, 76(r3) | |
| 782 | l.lwz r20, 80(r3) | |
| 783 | l.lwz r21, 84(r3) | |
| 784 | l.lwz r22, 88(r3) | |
| 785 | l.lwz r23, 92(r3) | |
| 786 | l.lwz r24, 96(r3) | |
| 787 | l.lwz r25,100(r3) | |
| 788 | l.lwz r26,104(r3) | |
| 789 | l.lwz r27,108(r3) | |
| 790 | l.lwz r28,112(r3) | |
| 791 | l.lwz r29,116(r3) | |
| 792 | l.lwz r30,120(r3) | |
| 793 | l.lwz r31,124(r3) | |
| 794 | ||
| 795 | # at last, restore r3 | |
| 796 | l.lwz r3, 12(r3) | |
| 797 | ||
| 798 | # load new pc into ra | |
| 799 | l.lwz r9, 128(r3) | |
| 800 | # jump to pc | |
| 801 | l.jr r9 | |
| 802 | l.nop | |
| 803 | ||
| 804 | #elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32 | |
| 805 | ||
| 806 | // | |
| 807 | // void libunwind::Registers_mips_o32::jumpto() | |
| 808 | // | |
| 809 | // On entry: | |
| 810 | // thread state pointer is in a0 ($4) | |
| 811 | // | |
| 812 | DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind18Registers_mips_o326jumptoEv) | |
| 813 | .set push | |
| 814 | .set noat | |
| 815 | .set noreorder | |
| 816 | .set nomacro | |
| 817 | #ifdef __mips_hard_float | |
| 818 | #if __mips_fpr != 64 | |
| 819 | ldc1 $f0, (4 * 36 + 8 * 0)($4) | |
| 820 | ldc1 $f2, (4 * 36 + 8 * 2)($4) | |
| 821 | ldc1 $f4, (4 * 36 + 8 * 4)($4) | |
| 822 | ldc1 $f6, (4 * 36 + 8 * 6)($4) | |
| 823 | ldc1 $f8, (4 * 36 + 8 * 8)($4) | |
| 824 | ldc1 $f10, (4 * 36 + 8 * 10)($4) | |
| 825 | ldc1 $f12, (4 * 36 + 8 * 12)($4) | |
| 826 | ldc1 $f14, (4 * 36 + 8 * 14)($4) | |
| 827 | ldc1 $f16, (4 * 36 + 8 * 16)($4) | |
| 828 | ldc1 $f18, (4 * 36 + 8 * 18)($4) | |
| 829 | ldc1 $f20, (4 * 36 + 8 * 20)($4) | |
| 830 | ldc1 $f22, (4 * 36 + 8 * 22)($4) | |
| 831 | ldc1 $f24, (4 * 36 + 8 * 24)($4) | |
| 832 | ldc1 $f26, (4 * 36 + 8 * 26)($4) | |
| 833 | ldc1 $f28, (4 * 36 + 8 * 28)($4) | |
| 834 | ldc1 $f30, (4 * 36 + 8 * 30)($4) | |
| 835 | #else | |
| 836 | ldc1 $f0, (4 * 36 + 8 * 0)($4) | |
| 837 | ldc1 $f1, (4 * 36 + 8 * 1)($4) | |
| 838 | ldc1 $f2, (4 * 36 + 8 * 2)($4) | |
| 839 | ldc1 $f3, (4 * 36 + 8 * 3)($4) | |
| 840 | ldc1 $f4, (4 * 36 + 8 * 4)($4) | |
| 841 | ldc1 $f5, (4 * 36 + 8 * 5)($4) | |
| 842 | ldc1 $f6, (4 * 36 + 8 * 6)($4) | |
| 843 | ldc1 $f7, (4 * 36 + 8 * 7)($4) | |
| 844 | ldc1 $f8, (4 * 36 + 8 * 8)($4) | |
| 845 | ldc1 $f9, (4 * 36 + 8 * 9)($4) | |
| 846 | ldc1 $f10, (4 * 36 + 8 * 10)($4) | |
| 847 | ldc1 $f11, (4 * 36 + 8 * 11)($4) | |
| 848 | ldc1 $f12, (4 * 36 + 8 * 12)($4) | |
| 849 | ldc1 $f13, (4 * 36 + 8 * 13)($4) | |
| 850 | ldc1 $f14, (4 * 36 + 8 * 14)($4) | |
| 851 | ldc1 $f15, (4 * 36 + 8 * 15)($4) | |
| 852 | ldc1 $f16, (4 * 36 + 8 * 16)($4) | |
| 853 | ldc1 $f17, (4 * 36 + 8 * 17)($4) | |
| 854 | ldc1 $f18, (4 * 36 + 8 * 18)($4) | |
| 855 | ldc1 $f19, (4 * 36 + 8 * 19)($4) | |
| 856 | ldc1 $f20, (4 * 36 + 8 * 20)($4) | |
| 857 | ldc1 $f21, (4 * 36 + 8 * 21)($4) | |
| 858 | ldc1 $f22, (4 * 36 + 8 * 22)($4) | |
| 859 | ldc1 $f23, (4 * 36 + 8 * 23)($4) | |
| 860 | ldc1 $f24, (4 * 36 + 8 * 24)($4) | |
| 861 | ldc1 $f25, (4 * 36 + 8 * 25)($4) | |
| 862 | ldc1 $f26, (4 * 36 + 8 * 26)($4) | |
| 863 | ldc1 $f27, (4 * 36 + 8 * 27)($4) | |
| 864 | ldc1 $f28, (4 * 36 + 8 * 28)($4) | |
| 865 | ldc1 $f29, (4 * 36 + 8 * 29)($4) | |
| 866 | ldc1 $f30, (4 * 36 + 8 * 30)($4) | |
| 867 | ldc1 $f31, (4 * 36 + 8 * 31)($4) | |
| 868 | #endif | |
| 869 | #endif | |
| 870 | // restore hi and lo | |
| 871 | lw $8, (4 * 33)($4) | |
| 872 | mthi $8 | |
| 873 | lw $8, (4 * 34)($4) | |
| 874 | mtlo $8 | |
| 875 | // r0 is zero | |
| 876 | lw $1, (4 * 1)($4) | |
| 877 | lw $2, (4 * 2)($4) | |
| 878 | lw $3, (4 * 3)($4) | |
| 879 | // skip a0 for now | |
| 880 | lw $5, (4 * 5)($4) | |
| 881 | lw $6, (4 * 6)($4) | |
| 882 | lw $7, (4 * 7)($4) | |
| 883 | lw $8, (4 * 8)($4) | |
| 884 | lw $9, (4 * 9)($4) | |
| 885 | lw $10, (4 * 10)($4) | |
| 886 | lw $11, (4 * 11)($4) | |
| 887 | lw $12, (4 * 12)($4) | |
| 888 | lw $13, (4 * 13)($4) | |
| 889 | lw $14, (4 * 14)($4) | |
| 890 | lw $15, (4 * 15)($4) | |
| 891 | lw $16, (4 * 16)($4) | |
| 892 | lw $17, (4 * 17)($4) | |
| 893 | lw $18, (4 * 18)($4) | |
| 894 | lw $19, (4 * 19)($4) | |
| 895 | lw $20, (4 * 20)($4) | |
| 896 | lw $21, (4 * 21)($4) | |
| 897 | lw $22, (4 * 22)($4) | |
| 898 | lw $23, (4 * 23)($4) | |
| 899 | lw $24, (4 * 24)($4) | |
| 900 | lw $25, (4 * 25)($4) | |
| 901 | lw $26, (4 * 26)($4) | |
| 902 | lw $27, (4 * 27)($4) | |
| 903 | lw $28, (4 * 28)($4) | |
| 904 | lw $29, (4 * 29)($4) | |
| 905 | lw $30, (4 * 30)($4) | |
| 906 | // load new pc into ra | |
| 907 | lw $31, (4 * 32)($4) | |
| 908 | // jump to ra, load a0 in the delay slot | |
| 909 | jr $31 | |
| 910 | lw $4, (4 * 4)($4) | |
| 911 | .set pop | |
| 912 | ||
| 913 | #elif defined(__mips64) | |
| 914 | ||
| 915 | // | |
| 916 | // void libunwind::Registers_mips_newabi::jumpto() | |
| 917 | // | |
| 918 | // On entry: | |
| 919 | // thread state pointer is in a0 ($4) | |
| 920 | // | |
| 921 | DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind21Registers_mips_newabi6jumptoEv) | |
| 922 | .set push | |
| 923 | .set noat | |
| 924 | .set noreorder | |
| 925 | .set nomacro | |
| 926 | #ifdef __mips_hard_float | |
| 927 | ldc1 $f0, (8 * 35)($4) | |
| 928 | ldc1 $f1, (8 * 36)($4) | |
| 929 | ldc1 $f2, (8 * 37)($4) | |
| 930 | ldc1 $f3, (8 * 38)($4) | |
| 931 | ldc1 $f4, (8 * 39)($4) | |
| 932 | ldc1 $f5, (8 * 40)($4) | |
| 933 | ldc1 $f6, (8 * 41)($4) | |
| 934 | ldc1 $f7, (8 * 42)($4) | |
| 935 | ldc1 $f8, (8 * 43)($4) | |
| 936 | ldc1 $f9, (8 * 44)($4) | |
| 937 | ldc1 $f10, (8 * 45)($4) | |
| 938 | ldc1 $f11, (8 * 46)($4) | |
| 939 | ldc1 $f12, (8 * 47)($4) | |
| 940 | ldc1 $f13, (8 * 48)($4) | |
| 941 | ldc1 $f14, (8 * 49)($4) | |
| 942 | ldc1 $f15, (8 * 50)($4) | |
| 943 | ldc1 $f16, (8 * 51)($4) | |
| 944 | ldc1 $f17, (8 * 52)($4) | |
| 945 | ldc1 $f18, (8 * 53)($4) | |
| 946 | ldc1 $f19, (8 * 54)($4) | |
| 947 | ldc1 $f20, (8 * 55)($4) | |
| 948 | ldc1 $f21, (8 * 56)($4) | |
| 949 | ldc1 $f22, (8 * 57)($4) | |
| 950 | ldc1 $f23, (8 * 58)($4) | |
| 951 | ldc1 $f24, (8 * 59)($4) | |
| 952 | ldc1 $f25, (8 * 60)($4) | |
| 953 | ldc1 $f26, (8 * 61)($4) | |
| 954 | ldc1 $f27, (8 * 62)($4) | |
| 955 | ldc1 $f28, (8 * 63)($4) | |
| 956 | ldc1 $f29, (8 * 64)($4) | |
| 957 | ldc1 $f30, (8 * 65)($4) | |
| 958 | ldc1 $f31, (8 * 66)($4) | |
| 959 | #endif | |
| 960 | // restore hi and lo | |
| 961 | ld $8, (8 * 33)($4) | |
| 962 | mthi $8 | |
| 963 | ld $8, (8 * 34)($4) | |
| 964 | mtlo $8 | |
| 965 | // r0 is zero | |
| 966 | ld $1, (8 * 1)($4) | |
| 967 | ld $2, (8 * 2)($4) | |
| 968 | ld $3, (8 * 3)($4) | |
| 969 | // skip a0 for now | |
| 970 | ld $5, (8 * 5)($4) | |
| 971 | ld $6, (8 * 6)($4) | |
| 972 | ld $7, (8 * 7)($4) | |
| 973 | ld $8, (8 * 8)($4) | |
| 974 | ld $9, (8 * 9)($4) | |
| 975 | ld $10, (8 * 10)($4) | |
| 976 | ld $11, (8 * 11)($4) | |
| 977 | ld $12, (8 * 12)($4) | |
| 978 | ld $13, (8 * 13)($4) | |
| 979 | ld $14, (8 * 14)($4) | |
| 980 | ld $15, (8 * 15)($4) | |
| 981 | ld $16, (8 * 16)($4) | |
| 982 | ld $17, (8 * 17)($4) | |
| 983 | ld $18, (8 * 18)($4) | |
| 984 | ld $19, (8 * 19)($4) | |
| 985 | ld $20, (8 * 20)($4) | |
| 986 | ld $21, (8 * 21)($4) | |
| 987 | ld $22, (8 * 22)($4) | |
| 988 | ld $23, (8 * 23)($4) | |
| 989 | ld $24, (8 * 24)($4) | |
| 990 | ld $25, (8 * 25)($4) | |
| 991 | ld $26, (8 * 26)($4) | |
| 992 | ld $27, (8 * 27)($4) | |
| 993 | ld $28, (8 * 28)($4) | |
| 994 | ld $29, (8 * 29)($4) | |
| 995 | ld $30, (8 * 30)($4) | |
| 996 | // load new pc into ra | |
| 997 | ld $31, (8 * 32)($4) | |
| 998 | // jump to ra, load a0 in the delay slot | |
| 999 | jr $31 | |
| 1000 | ld $4, (8 * 4)($4) | |
| 1001 | .set pop | |
| 1002 | ||
| 1003 | #elif defined(__sparc__) | |
| 1004 | ||
| 1005 | // | |
| 1006 | // void libunwind::Registers_sparc_o32::jumpto() | |
| 1007 | // | |
| 1008 | // On entry: | |
| 1009 | // thread_state pointer is in o0 | |
| 1010 | // | |
| 1011 | DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind15Registers_sparc6jumptoEv) | |
| 1012 | ta 3 | |
| 1013 | ldd [%o0 + 64], %l0 | |
| 1014 | ldd [%o0 + 72], %l2 | |
| 1015 | ldd [%o0 + 80], %l4 | |
| 1016 | ldd [%o0 + 88], %l6 | |
| 1017 | ldd [%o0 + 96], %i0 | |
| 1018 | ldd [%o0 + 104], %i2 | |
| 1019 | ldd [%o0 + 112], %i4 | |
| 1020 | ldd [%o0 + 120], %i6 | |
| 1021 | ld [%o0 + 60], %o7 | |
| 1022 | jmp %o7 | |
| 1023 | nop | |
| 1024 | ||
| 1025 | #endif | |
| 1026 | ||
| 1027 | #endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */ | |
| 1028 | ||
| 1029 | NO_EXEC_STACK_DIRECTIVE | |
| 1030 |
libunwind/src/UnwindRegistersSave.S created+978| ... | ... | @@ -0,0 +1,978 @@ |
| 1 | //===------------------------ UnwindRegistersSave.S -----------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is dual licensed under the MIT and the University of Illinois Open | |
| 6 | // Source Licenses. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | //===----------------------------------------------------------------------===// | |
| 9 | ||
| 10 | #include "assembly.h" | |
| 11 | ||
| 12 | .text | |
| 13 | ||
| 14 | #if !defined(__USING_SJLJ_EXCEPTIONS__) | |
| 15 | ||
| 16 | #if defined(__i386__) | |
| 17 | ||
| 18 | # | |
| 19 | # extern int unw_getcontext(unw_context_t* thread_state) | |
| 20 | # | |
| 21 | # On entry: | |
| 22 | # + + | |
| 23 | # +-----------------------+ | |
| 24 | # + thread_state pointer + | |
| 25 | # +-----------------------+ | |
| 26 | # + return address + | |
| 27 | # +-----------------------+ <-- SP | |
| 28 | # + + | |
| 29 | # | |
| 30 | DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) | |
| 31 | push %eax | |
| 32 | movl 8(%esp), %eax | |
| 33 | movl %ebx, 4(%eax) | |
| 34 | movl %ecx, 8(%eax) | |
| 35 | movl %edx, 12(%eax) | |
| 36 | movl %edi, 16(%eax) | |
| 37 | movl %esi, 20(%eax) | |
| 38 | movl %ebp, 24(%eax) | |
| 39 | movl %esp, %edx | |
| 40 | addl $8, %edx | |
| 41 | movl %edx, 28(%eax) # store what sp was at call site as esp | |
| 42 | # skip ss | |
| 43 | # skip eflags | |
| 44 | movl 4(%esp), %edx | |
| 45 | movl %edx, 40(%eax) # store return address as eip | |
| 46 | # skip cs | |
| 47 | # skip ds | |
| 48 | # skip es | |
| 49 | # skip fs | |
| 50 | # skip gs | |
| 51 | movl (%esp), %edx | |
| 52 | movl %edx, (%eax) # store original eax | |
| 53 | popl %eax | |
| 54 | xorl %eax, %eax # return UNW_ESUCCESS | |
| 55 | ret | |
| 56 | ||
| 57 | #elif defined(__x86_64__) | |
| 58 | ||
| 59 | # | |
| 60 | # extern int unw_getcontext(unw_context_t* thread_state) | |
| 61 | # | |
| 62 | # On entry: | |
| 63 | # thread_state pointer is in rdi | |
| 64 | # | |
| 65 | DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) | |
| 66 | #if defined(_WIN64) | |
| 67 | #define PTR %rcx | |
| 68 | #define TMP %rdx | |
| 69 | #else | |
| 70 | #define PTR %rdi | |
| 71 | #define TMP %rsi | |
| 72 | #endif | |
| 73 | ||
| 74 | movq %rax, (PTR) | |
| 75 | movq %rbx, 8(PTR) | |
| 76 | movq %rcx, 16(PTR) | |
| 77 | movq %rdx, 24(PTR) | |
| 78 | movq %rdi, 32(PTR) | |
| 79 | movq %rsi, 40(PTR) | |
| 80 | movq %rbp, 48(PTR) | |
| 81 | movq %rsp, 56(PTR) | |
| 82 | addq $8, 56(PTR) | |
| 83 | movq %r8, 64(PTR) | |
| 84 | movq %r9, 72(PTR) | |
| 85 | movq %r10, 80(PTR) | |
| 86 | movq %r11, 88(PTR) | |
| 87 | movq %r12, 96(PTR) | |
| 88 | movq %r13,104(PTR) | |
| 89 | movq %r14,112(PTR) | |
| 90 | movq %r15,120(PTR) | |
| 91 | movq (%rsp),TMP | |
| 92 | movq TMP,128(PTR) # store return address as rip | |
| 93 | # skip rflags | |
| 94 | # skip cs | |
| 95 | # skip fs | |
| 96 | # skip gs | |
| 97 | ||
| 98 | #if defined(_WIN64) | |
| 99 | movdqu %xmm0,176(PTR) | |
| 100 | movdqu %xmm1,192(PTR) | |
| 101 | movdqu %xmm2,208(PTR) | |
| 102 | movdqu %xmm3,224(PTR) | |
| 103 | movdqu %xmm4,240(PTR) | |
| 104 | movdqu %xmm5,256(PTR) | |
| 105 | movdqu %xmm6,272(PTR) | |
| 106 | movdqu %xmm7,288(PTR) | |
| 107 | movdqu %xmm8,304(PTR) | |
| 108 | movdqu %xmm9,320(PTR) | |
| 109 | movdqu %xmm10,336(PTR) | |
| 110 | movdqu %xmm11,352(PTR) | |
| 111 | movdqu %xmm12,368(PTR) | |
| 112 | movdqu %xmm13,384(PTR) | |
| 113 | movdqu %xmm14,400(PTR) | |
| 114 | movdqu %xmm15,416(PTR) | |
| 115 | #endif | |
| 116 | xorl %eax, %eax # return UNW_ESUCCESS | |
| 117 | ret | |
| 118 | ||
| 119 | #elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32 | |
| 120 | ||
| 121 | # | |
| 122 | # extern int unw_getcontext(unw_context_t* thread_state) | |
| 123 | # | |
| 124 | # On entry: | |
| 125 | # thread_state pointer is in a0 ($4) | |
| 126 | # | |
| 127 | DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) | |
| 128 | .set push | |
| 129 | .set noat | |
| 130 | .set noreorder | |
| 131 | .set nomacro | |
| 132 | sw $1, (4 * 1)($4) | |
| 133 | sw $2, (4 * 2)($4) | |
| 134 | sw $3, (4 * 3)($4) | |
| 135 | sw $4, (4 * 4)($4) | |
| 136 | sw $5, (4 * 5)($4) | |
| 137 | sw $6, (4 * 6)($4) | |
| 138 | sw $7, (4 * 7)($4) | |
| 139 | sw $8, (4 * 8)($4) | |
| 140 | sw $9, (4 * 9)($4) | |
| 141 | sw $10, (4 * 10)($4) | |
| 142 | sw $11, (4 * 11)($4) | |
| 143 | sw $12, (4 * 12)($4) | |
| 144 | sw $13, (4 * 13)($4) | |
| 145 | sw $14, (4 * 14)($4) | |
| 146 | sw $15, (4 * 15)($4) | |
| 147 | sw $16, (4 * 16)($4) | |
| 148 | sw $17, (4 * 17)($4) | |
| 149 | sw $18, (4 * 18)($4) | |
| 150 | sw $19, (4 * 19)($4) | |
| 151 | sw $20, (4 * 20)($4) | |
| 152 | sw $21, (4 * 21)($4) | |
| 153 | sw $22, (4 * 22)($4) | |
| 154 | sw $23, (4 * 23)($4) | |
| 155 | sw $24, (4 * 24)($4) | |
| 156 | sw $25, (4 * 25)($4) | |
| 157 | sw $26, (4 * 26)($4) | |
| 158 | sw $27, (4 * 27)($4) | |
| 159 | sw $28, (4 * 28)($4) | |
| 160 | sw $29, (4 * 29)($4) | |
| 161 | sw $30, (4 * 30)($4) | |
| 162 | sw $31, (4 * 31)($4) | |
| 163 | # Store return address to pc | |
| 164 | sw $31, (4 * 32)($4) | |
| 165 | # hi and lo | |
| 166 | mfhi $8 | |
| 167 | sw $8, (4 * 33)($4) | |
| 168 | mflo $8 | |
| 169 | sw $8, (4 * 34)($4) | |
| 170 | #ifdef __mips_hard_float | |
| 171 | #if __mips_fpr != 64 | |
| 172 | sdc1 $f0, (4 * 36 + 8 * 0)($4) | |
| 173 | sdc1 $f2, (4 * 36 + 8 * 2)($4) | |
| 174 | sdc1 $f4, (4 * 36 + 8 * 4)($4) | |
| 175 | sdc1 $f6, (4 * 36 + 8 * 6)($4) | |
| 176 | sdc1 $f8, (4 * 36 + 8 * 8)($4) | |
| 177 | sdc1 $f10, (4 * 36 + 8 * 10)($4) | |
| 178 | sdc1 $f12, (4 * 36 + 8 * 12)($4) | |
| 179 | sdc1 $f14, (4 * 36 + 8 * 14)($4) | |
| 180 | sdc1 $f16, (4 * 36 + 8 * 16)($4) | |
| 181 | sdc1 $f18, (4 * 36 + 8 * 18)($4) | |
| 182 | sdc1 $f20, (4 * 36 + 8 * 20)($4) | |
| 183 | sdc1 $f22, (4 * 36 + 8 * 22)($4) | |
| 184 | sdc1 $f24, (4 * 36 + 8 * 24)($4) | |
| 185 | sdc1 $f26, (4 * 36 + 8 * 26)($4) | |
| 186 | sdc1 $f28, (4 * 36 + 8 * 28)($4) | |
| 187 | sdc1 $f30, (4 * 36 + 8 * 30)($4) | |
| 188 | #else | |
| 189 | sdc1 $f0, (4 * 36 + 8 * 0)($4) | |
| 190 | sdc1 $f1, (4 * 36 + 8 * 1)($4) | |
| 191 | sdc1 $f2, (4 * 36 + 8 * 2)($4) | |
| 192 | sdc1 $f3, (4 * 36 + 8 * 3)($4) | |
| 193 | sdc1 $f4, (4 * 36 + 8 * 4)($4) | |
| 194 | sdc1 $f5, (4 * 36 + 8 * 5)($4) | |
| 195 | sdc1 $f6, (4 * 36 + 8 * 6)($4) | |
| 196 | sdc1 $f7, (4 * 36 + 8 * 7)($4) | |
| 197 | sdc1 $f8, (4 * 36 + 8 * 8)($4) | |
| 198 | sdc1 $f9, (4 * 36 + 8 * 9)($4) | |
| 199 | sdc1 $f10, (4 * 36 + 8 * 10)($4) | |
| 200 | sdc1 $f11, (4 * 36 + 8 * 11)($4) | |
| 201 | sdc1 $f12, (4 * 36 + 8 * 12)($4) | |
| 202 | sdc1 $f13, (4 * 36 + 8 * 13)($4) | |
| 203 | sdc1 $f14, (4 * 36 + 8 * 14)($4) | |
| 204 | sdc1 $f15, (4 * 36 + 8 * 15)($4) | |
| 205 | sdc1 $f16, (4 * 36 + 8 * 16)($4) | |
| 206 | sdc1 $f17, (4 * 36 + 8 * 17)($4) | |
| 207 | sdc1 $f18, (4 * 36 + 8 * 18)($4) | |
| 208 | sdc1 $f19, (4 * 36 + 8 * 19)($4) | |
| 209 | sdc1 $f20, (4 * 36 + 8 * 20)($4) | |
| 210 | sdc1 $f21, (4 * 36 + 8 * 21)($4) | |
| 211 | sdc1 $f22, (4 * 36 + 8 * 22)($4) | |
| 212 | sdc1 $f23, (4 * 36 + 8 * 23)($4) | |
| 213 | sdc1 $f24, (4 * 36 + 8 * 24)($4) | |
| 214 | sdc1 $f25, (4 * 36 + 8 * 25)($4) | |
| 215 | sdc1 $f26, (4 * 36 + 8 * 26)($4) | |
| 216 | sdc1 $f27, (4 * 36 + 8 * 27)($4) | |
| 217 | sdc1 $f28, (4 * 36 + 8 * 28)($4) | |
| 218 | sdc1 $f29, (4 * 36 + 8 * 29)($4) | |
| 219 | sdc1 $f30, (4 * 36 + 8 * 30)($4) | |
| 220 | sdc1 $f31, (4 * 36 + 8 * 31)($4) | |
| 221 | #endif | |
| 222 | #endif | |
| 223 | jr	$31 | |
| 224 | # return UNW_ESUCCESS | |
| 225 | or $2, $0, $0 | |
| 226 | .set pop | |
| 227 | ||
| 228 | #elif defined(__mips64) | |
| 229 | ||
| 230 | # | |
| 231 | # extern int unw_getcontext(unw_context_t* thread_state) | |
| 232 | # | |
| 233 | # On entry: | |
| 234 | # thread_state pointer is in a0 ($4) | |
| 235 | # | |
| 236 | DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) | |
| 237 | .set push | |
| 238 | .set noat | |
| 239 | .set noreorder | |
| 240 | .set nomacro | |
| 241 | sd $1, (8 * 1)($4) | |
| 242 | sd $2, (8 * 2)($4) | |
| 243 | sd $3, (8 * 3)($4) | |
| 244 | sd $4, (8 * 4)($4) | |
| 245 | sd $5, (8 * 5)($4) | |
| 246 | sd $6, (8 * 6)($4) | |
| 247 | sd $7, (8 * 7)($4) | |
| 248 | sd $8, (8 * 8)($4) | |
| 249 | sd $9, (8 * 9)($4) | |
| 250 | sd $10, (8 * 10)($4) | |
| 251 | sd $11, (8 * 11)($4) | |
| 252 | sd $12, (8 * 12)($4) | |
| 253 | sd $13, (8 * 13)($4) | |
| 254 | sd $14, (8 * 14)($4) | |
| 255 | sd $15, (8 * 15)($4) | |
| 256 | sd $16, (8 * 16)($4) | |
| 257 | sd $17, (8 * 17)($4) | |
| 258 | sd $18, (8 * 18)($4) | |
| 259 | sd $19, (8 * 19)($4) | |
| 260 | sd $20, (8 * 20)($4) | |
| 261 | sd $21, (8 * 21)($4) | |
| 262 | sd $22, (8 * 22)($4) | |
| 263 | sd $23, (8 * 23)($4) | |
| 264 | sd $24, (8 * 24)($4) | |
| 265 | sd $25, (8 * 25)($4) | |
| 266 | sd $26, (8 * 26)($4) | |
| 267 | sd $27, (8 * 27)($4) | |
| 268 | sd $28, (8 * 28)($4) | |
| 269 | sd $29, (8 * 29)($4) | |
| 270 | sd $30, (8 * 30)($4) | |
| 271 | sd $31, (8 * 31)($4) | |
| 272 | # Store return address to pc | |
| 273 | sd $31, (8 * 32)($4) | |
| 274 | # hi and lo | |
| 275 | mfhi $8 | |
| 276 | sd $8, (8 * 33)($4) | |
| 277 | mflo $8 | |
| 278 | sd $8, (8 * 34)($4) | |
| 279 | #ifdef __mips_hard_float | |
| 280 | sdc1 $f0, (8 * 35)($4) | |
| 281 | sdc1 $f1, (8 * 36)($4) | |
| 282 | sdc1 $f2, (8 * 37)($4) | |
| 283 | sdc1 $f3, (8 * 38)($4) | |
| 284 | sdc1 $f4, (8 * 39)($4) | |
| 285 | sdc1 $f5, (8 * 40)($4) | |
| 286 | sdc1 $f6, (8 * 41)($4) | |
| 287 | sdc1 $f7, (8 * 42)($4) | |
| 288 | sdc1 $f8, (8 * 43)($4) | |
| 289 | sdc1 $f9, (8 * 44)($4) | |
| 290 | sdc1 $f10, (8 * 45)($4) | |
| 291 | sdc1 $f11, (8 * 46)($4) | |
| 292 | sdc1 $f12, (8 * 47)($4) | |
| 293 | sdc1 $f13, (8 * 48)($4) | |
| 294 | sdc1 $f14, (8 * 49)($4) | |
| 295 | sdc1 $f15, (8 * 50)($4) | |
| 296 | sdc1 $f16, (8 * 51)($4) | |
| 297 | sdc1 $f17, (8 * 52)($4) | |
| 298 | sdc1 $f18, (8 * 53)($4) | |
| 299 | sdc1 $f19, (8 * 54)($4) | |
| 300 | sdc1 $f20, (8 * 55)($4) | |
| 301 | sdc1 $f21, (8 * 56)($4) | |
| 302 | sdc1 $f22, (8 * 57)($4) | |
| 303 | sdc1 $f23, (8 * 58)($4) | |
| 304 | sdc1 $f24, (8 * 59)($4) | |
| 305 | sdc1 $f25, (8 * 60)($4) | |
| 306 | sdc1 $f26, (8 * 61)($4) | |
| 307 | sdc1 $f27, (8 * 62)($4) | |
| 308 | sdc1 $f28, (8 * 63)($4) | |
| 309 | sdc1 $f29, (8 * 64)($4) | |
| 310 | sdc1 $f30, (8 * 65)($4) | |
| 311 | sdc1 $f31, (8 * 66)($4) | |
| 312 | #endif | |
| 313 | jr	$31 | |
| 314 | # return UNW_ESUCCESS | |
| 315 | or $2, $0, $0 | |
| 316 | .set pop | |
| 317 | ||
| 318 | # elif defined(__mips__) | |
| 319 | ||
| 320 | # | |
| 321 | # extern int unw_getcontext(unw_context_t* thread_state) | |
| 322 | # | |
| 323 | # Just trap for the time being. | |
| 324 | DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) | |
| 325 | teq $0, $0 | |
| 326 | ||
| 327 | #elif defined(__powerpc64__) | |
| 328 | ||
| 329 | // | |
| 330 | // extern int unw_getcontext(unw_context_t* thread_state) | |
| 331 | // | |
| 332 | // On entry: | |
| 333 | // thread_state pointer is in r3 | |
| 334 | // | |
| 335 | DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) | |
| 336 | ||
| 337 | // store register (GPR) | |
| 338 | #define PPC64_STR(n) \ | |
| 339 | std %r##n, (8 * (n + 2))(%r3) | |
| 340 | ||
| 341 | // save GPRs | |
| 342 | PPC64_STR(0) | |
| 343 | mflr %r0 | |
| 344 | std %r0, PPC64_OFFS_SRR0(%r3) // store lr as ssr0 | |
| 345 | PPC64_STR(1) | |
| 346 | PPC64_STR(2) | |
| 347 | PPC64_STR(3) | |
| 348 | PPC64_STR(4) | |
| 349 | PPC64_STR(5) | |
| 350 | PPC64_STR(6) | |
| 351 | PPC64_STR(7) | |
| 352 | PPC64_STR(8) | |
| 353 | PPC64_STR(9) | |
| 354 | PPC64_STR(10) | |
| 355 | PPC64_STR(11) | |
| 356 | PPC64_STR(12) | |
| 357 | PPC64_STR(13) | |
| 358 | PPC64_STR(14) | |
| 359 | PPC64_STR(15) | |
| 360 | PPC64_STR(16) | |
| 361 | PPC64_STR(17) | |
| 362 | PPC64_STR(18) | |
| 363 | PPC64_STR(19) | |
| 364 | PPC64_STR(20) | |
| 365 | PPC64_STR(21) | |
| 366 | PPC64_STR(22) | |
| 367 | PPC64_STR(23) | |
| 368 | PPC64_STR(24) | |
| 369 | PPC64_STR(25) | |
| 370 | PPC64_STR(26) | |
| 371 | PPC64_STR(27) | |
| 372 | PPC64_STR(28) | |
| 373 | PPC64_STR(29) | |
| 374 | PPC64_STR(30) | |
| 375 | PPC64_STR(31) | |
| 376 | ||
| 377 | mfcr %r0 | |
| 378 | std %r0, PPC64_OFFS_CR(%r3) | |
| 379 | mfxer %r0 | |
| 380 | std %r0, PPC64_OFFS_XER(%r3) | |
| 381 | mflr %r0 | |
| 382 | std %r0, PPC64_OFFS_LR(%r3) | |
| 383 | mfctr %r0 | |
| 384 | std %r0, PPC64_OFFS_CTR(%r3) | |
| 385 | mfvrsave %r0 | |
| 386 | std %r0, PPC64_OFFS_VRSAVE(%r3) | |
| 387 | ||
| 388 | #ifdef PPC64_HAS_VMX | |
| 389 | // save VS registers | |
| 390 | // (note that this also saves floating point registers and V registers, | |
| 391 | // because part of VS is mapped to these registers) | |
| 392 | ||
| 393 | addi %r4, %r3, PPC64_OFFS_FP | |
| 394 | ||
| 395 | // store VS register | |
| 396 | #define PPC64_STVS(n) \ | |
| 397 | stxvd2x %vs##n, 0, %r4 ;\ | |
| 398 | addi %r4, %r4, 16 | |
| 399 | ||
| 400 | PPC64_STVS(0) | |
| 401 | PPC64_STVS(1) | |
| 402 | PPC64_STVS(2) | |
| 403 | PPC64_STVS(3) | |
| 404 | PPC64_STVS(4) | |
| 405 | PPC64_STVS(5) | |
| 406 | PPC64_STVS(6) | |
| 407 | PPC64_STVS(7) | |
| 408 | PPC64_STVS(8) | |
| 409 | PPC64_STVS(9) | |
| 410 | PPC64_STVS(10) | |
| 411 | PPC64_STVS(11) | |
| 412 | PPC64_STVS(12) | |
| 413 | PPC64_STVS(13) | |
| 414 | PPC64_STVS(14) | |
| 415 | PPC64_STVS(15) | |
| 416 | PPC64_STVS(16) | |
| 417 | PPC64_STVS(17) | |
| 418 | PPC64_STVS(18) | |
| 419 | PPC64_STVS(19) | |
| 420 | PPC64_STVS(20) | |
| 421 | PPC64_STVS(21) | |
| 422 | PPC64_STVS(22) | |
| 423 | PPC64_STVS(23) | |
| 424 | PPC64_STVS(24) | |
| 425 | PPC64_STVS(25) | |
| 426 | PPC64_STVS(26) | |
| 427 | PPC64_STVS(27) | |
| 428 | PPC64_STVS(28) | |
| 429 | PPC64_STVS(29) | |
| 430 | PPC64_STVS(30) | |
| 431 | PPC64_STVS(31) | |
| 432 | PPC64_STVS(32) | |
| 433 | PPC64_STVS(33) | |
| 434 | PPC64_STVS(34) | |
| 435 | PPC64_STVS(35) | |
| 436 | PPC64_STVS(36) | |
| 437 | PPC64_STVS(37) | |
| 438 | PPC64_STVS(38) | |
| 439 | PPC64_STVS(39) | |
| 440 | PPC64_STVS(40) | |
| 441 | PPC64_STVS(41) | |
| 442 | PPC64_STVS(42) | |
| 443 | PPC64_STVS(43) | |
| 444 | PPC64_STVS(44) | |
| 445 | PPC64_STVS(45) | |
| 446 | PPC64_STVS(46) | |
| 447 | PPC64_STVS(47) | |
| 448 | PPC64_STVS(48) | |
| 449 | PPC64_STVS(49) | |
| 450 | PPC64_STVS(50) | |
| 451 | PPC64_STVS(51) | |
| 452 | PPC64_STVS(52) | |
| 453 | PPC64_STVS(53) | |
| 454 | PPC64_STVS(54) | |
| 455 | PPC64_STVS(55) | |
| 456 | PPC64_STVS(56) | |
| 457 | PPC64_STVS(57) | |
| 458 | PPC64_STVS(58) | |
| 459 | PPC64_STVS(59) | |
| 460 | PPC64_STVS(60) | |
| 461 | PPC64_STVS(61) | |
| 462 | PPC64_STVS(62) | |
| 463 | PPC64_STVS(63) | |
| 464 | ||
| 465 | #else | |
| 466 | ||
| 467 | // store FP register | |
| 468 | #define PPC64_STF(n) \ | |
| 469 | stfd %f##n, (PPC64_OFFS_FP + n * 16)(%r3) | |
| 470 | ||
| 471 | // save float registers | |
| 472 | PPC64_STF(0) | |
| 473 | PPC64_STF(1) | |
| 474 | PPC64_STF(2) | |
| 475 | PPC64_STF(3) | |
| 476 | PPC64_STF(4) | |
| 477 | PPC64_STF(5) | |
| 478 | PPC64_STF(6) | |
| 479 | PPC64_STF(7) | |
| 480 | PPC64_STF(8) | |
| 481 | PPC64_STF(9) | |
| 482 | PPC64_STF(10) | |
| 483 | PPC64_STF(11) | |
| 484 | PPC64_STF(12) | |
| 485 | PPC64_STF(13) | |
| 486 | PPC64_STF(14) | |
| 487 | PPC64_STF(15) | |
| 488 | PPC64_STF(16) | |
| 489 | PPC64_STF(17) | |
| 490 | PPC64_STF(18) | |
| 491 | PPC64_STF(19) | |
| 492 | PPC64_STF(20) | |
| 493 | PPC64_STF(21) | |
| 494 | PPC64_STF(22) | |
| 495 | PPC64_STF(23) | |
| 496 | PPC64_STF(24) | |
| 497 | PPC64_STF(25) | |
| 498 | PPC64_STF(26) | |
| 499 | PPC64_STF(27) | |
| 500 | PPC64_STF(28) | |
| 501 | PPC64_STF(29) | |
| 502 | PPC64_STF(30) | |
| 503 | PPC64_STF(31) | |
| 504 | ||
| 505 | // save vector registers | |
| 506 | ||
| 507 | // Use 16-bytes below the stack pointer as an | |
| 508 | // aligned buffer to save each vector register. | |
| 509 | // Note that the stack pointer is always 16-byte aligned. | |
| 510 | subi %r4, %r1, 16 | |
| 511 | ||
| 512 | #define PPC64_STV_UNALIGNED(n) \ | |
| 513 | stvx %v##n, 0, %r4 ;\ | |
| 514 | ld %r5, 0(%r4) ;\ | |
| 515 | std %r5, (PPC64_OFFS_V + n * 16)(%r3) ;\ | |
| 516 | ld %r5, 8(%r4) ;\ | |
| 517 | std %r5, (PPC64_OFFS_V + n * 16 + 8)(%r3) | |
| 518 | ||
| 519 | PPC64_STV_UNALIGNED(0) | |
| 520 | PPC64_STV_UNALIGNED(1) | |
| 521 | PPC64_STV_UNALIGNED(2) | |
| 522 | PPC64_STV_UNALIGNED(3) | |
| 523 | PPC64_STV_UNALIGNED(4) | |
| 524 | PPC64_STV_UNALIGNED(5) | |
| 525 | PPC64_STV_UNALIGNED(6) | |
| 526 | PPC64_STV_UNALIGNED(7) | |
| 527 | PPC64_STV_UNALIGNED(8) | |
| 528 | PPC64_STV_UNALIGNED(9) | |
| 529 | PPC64_STV_UNALIGNED(10) | |
| 530 | PPC64_STV_UNALIGNED(11) | |
| 531 | PPC64_STV_UNALIGNED(12) | |
| 532 | PPC64_STV_UNALIGNED(13) | |
| 533 | PPC64_STV_UNALIGNED(14) | |
| 534 | PPC64_STV_UNALIGNED(15) | |
| 535 | PPC64_STV_UNALIGNED(16) | |
| 536 | PPC64_STV_UNALIGNED(17) | |
| 537 | PPC64_STV_UNALIGNED(18) | |
| 538 | PPC64_STV_UNALIGNED(19) | |
| 539 | PPC64_STV_UNALIGNED(20) | |
| 540 | PPC64_STV_UNALIGNED(21) | |
| 541 | PPC64_STV_UNALIGNED(22) | |
| 542 | PPC64_STV_UNALIGNED(23) | |
| 543 | PPC64_STV_UNALIGNED(24) | |
| 544 | PPC64_STV_UNALIGNED(25) | |
| 545 | PPC64_STV_UNALIGNED(26) | |
| 546 | PPC64_STV_UNALIGNED(27) | |
| 547 | PPC64_STV_UNALIGNED(28) | |
| 548 | PPC64_STV_UNALIGNED(29) | |
| 549 | PPC64_STV_UNALIGNED(30) | |
| 550 | PPC64_STV_UNALIGNED(31) | |
| 551 | ||
| 552 | #endif | |
| 553 | ||
| 554 | li %r3, 0 // return UNW_ESUCCESS | |
| 555 | blr | |
| 556 | ||
| 557 | ||
| 558 | #elif defined(__ppc__) | |
| 559 | ||
| 560 | ; | |
| 561 | ; extern int unw_getcontext(unw_context_t* thread_state) | |
| 562 | ; | |
| 563 | ; On entry: | |
| 564 | ; thread_state pointer is in r3 | |
| 565 | ; | |
| 566 | DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) | |
| 567 | stw r0, 8(r3) | |
| 568 | mflr r0 | |
| 569 | stw r0, 0(r3) ; store lr as ssr0 | |
| 570 | stw r1, 12(r3) | |
| 571 | stw r2, 16(r3) | |
| 572 | stw r3, 20(r3) | |
| 573 | stw r4, 24(r3) | |
| 574 | stw r5, 28(r3) | |
| 575 | stw r6, 32(r3) | |
| 576 | stw r7, 36(r3) | |
| 577 | stw r8, 40(r3) | |
| 578 | stw r9, 44(r3) | |
| 579 | stw r10, 48(r3) | |
| 580 | stw r11, 52(r3) | |
| 581 | stw r12, 56(r3) | |
| 582 | stw r13, 60(r3) | |
| 583 | stw r14, 64(r3) | |
| 584 | stw r15, 68(r3) | |
| 585 | stw r16, 72(r3) | |
| 586 | stw r17, 76(r3) | |
| 587 | stw r18, 80(r3) | |
| 588 | stw r19, 84(r3) | |
| 589 | stw r20, 88(r3) | |
| 590 | stw r21, 92(r3) | |
| 591 | stw r22, 96(r3) | |
| 592 | stw r23,100(r3) | |
| 593 | stw r24,104(r3) | |
| 594 | stw r25,108(r3) | |
| 595 | stw r26,112(r3) | |
| 596 | stw r27,116(r3) | |
| 597 | stw r28,120(r3) | |
| 598 | stw r29,124(r3) | |
| 599 | stw r30,128(r3) | |
| 600 | stw r31,132(r3) | |
| 601 | ||
| 602 | ; save VRSave register | |
| 603 | mfspr r0,256 | |
| 604 | stw r0,156(r3) | |
| 605 | ; save CR registers | |
| 606 | mfcr r0 | |
| 607 | stw r0,136(r3) | |
| 608 | ; save CTR register | |
| 609 | mfctr r0 | |
| 610 | stw r0,148(r3) | |
| 611 | ||
| 612 | ; save float registers | |
| 613 | stfd f0, 160(r3) | |
| 614 | stfd f1, 168(r3) | |
| 615 | stfd f2, 176(r3) | |
| 616 | stfd f3, 184(r3) | |
| 617 | stfd f4, 192(r3) | |
| 618 | stfd f5, 200(r3) | |
| 619 | stfd f6, 208(r3) | |
| 620 | stfd f7, 216(r3) | |
| 621 | stfd f8, 224(r3) | |
| 622 | stfd f9, 232(r3) | |
| 623 | stfd f10,240(r3) | |
| 624 | stfd f11,248(r3) | |
| 625 | stfd f12,256(r3) | |
| 626 | stfd f13,264(r3) | |
| 627 | stfd f14,272(r3) | |
| 628 | stfd f15,280(r3) | |
| 629 | stfd f16,288(r3) | |
| 630 | stfd f17,296(r3) | |
| 631 | stfd f18,304(r3) | |
| 632 | stfd f19,312(r3) | |
| 633 | stfd f20,320(r3) | |
| 634 | stfd f21,328(r3) | |
| 635 | stfd f22,336(r3) | |
| 636 | stfd f23,344(r3) | |
| 637 | stfd f24,352(r3) | |
| 638 | stfd f25,360(r3) | |
| 639 | stfd f26,368(r3) | |
| 640 | stfd f27,376(r3) | |
| 641 | stfd f28,384(r3) | |
| 642 | stfd f29,392(r3) | |
| 643 | stfd f30,400(r3) | |
| 644 | stfd f31,408(r3) | |
| 645 | ||
| 646 | ||
| 647 | ; save vector registers | |
| 648 | ||
| 649 | subi r4,r1,16 | |
| 650 | rlwinm r4,r4,0,0,27 ; mask low 4-bits | |
| 651 | ; r4 is now a 16-byte aligned pointer into the red zone | |
| 652 | ||
| 653 | #define SAVE_VECTOR_UNALIGNED(_vec, _offset) \ | |
| 654 | stvx _vec,0,r4 @\ | |
| 655 | lwz r5, 0(r4) @\ | |
| 656 | stw r5, _offset(r3) @\ | |
| 657 | lwz r5, 4(r4) @\ | |
| 658 | stw r5, _offset+4(r3) @\ | |
| 659 | lwz r5, 8(r4) @\ | |
| 660 | stw r5, _offset+8(r3) @\ | |
| 661 | lwz r5, 12(r4) @\ | |
| 662 | stw r5, _offset+12(r3) | |
| 663 | ||
| 664 | SAVE_VECTOR_UNALIGNED( v0, 424+0x000) | |
| 665 | SAVE_VECTOR_UNALIGNED( v1, 424+0x010) | |
| 666 | SAVE_VECTOR_UNALIGNED( v2, 424+0x020) | |
| 667 | SAVE_VECTOR_UNALIGNED( v3, 424+0x030) | |
| 668 | SAVE_VECTOR_UNALIGNED( v4, 424+0x040) | |
| 669 | SAVE_VECTOR_UNALIGNED( v5, 424+0x050) | |
| 670 | SAVE_VECTOR_UNALIGNED( v6, 424+0x060) | |
| 671 | SAVE_VECTOR_UNALIGNED( v7, 424+0x070) | |
| 672 | SAVE_VECTOR_UNALIGNED( v8, 424+0x080) | |
| 673 | SAVE_VECTOR_UNALIGNED( v9, 424+0x090) | |
| 674 | SAVE_VECTOR_UNALIGNED(v10, 424+0x0A0) | |
| 675 | SAVE_VECTOR_UNALIGNED(v11, 424+0x0B0) | |
| 676 | SAVE_VECTOR_UNALIGNED(v12, 424+0x0C0) | |
| 677 | SAVE_VECTOR_UNALIGNED(v13, 424+0x0D0) | |
| 678 | SAVE_VECTOR_UNALIGNED(v14, 424+0x0E0) | |
| 679 | SAVE_VECTOR_UNALIGNED(v15, 424+0x0F0) | |
| 680 | SAVE_VECTOR_UNALIGNED(v16, 424+0x100) | |
| 681 | SAVE_VECTOR_UNALIGNED(v17, 424+0x110) | |
| 682 | SAVE_VECTOR_UNALIGNED(v18, 424+0x120) | |
| 683 | SAVE_VECTOR_UNALIGNED(v19, 424+0x130) | |
| 684 | SAVE_VECTOR_UNALIGNED(v20, 424+0x140) | |
| 685 | SAVE_VECTOR_UNALIGNED(v21, 424+0x150) | |
| 686 | SAVE_VECTOR_UNALIGNED(v22, 424+0x160) | |
| 687 | SAVE_VECTOR_UNALIGNED(v23, 424+0x170) | |
| 688 | SAVE_VECTOR_UNALIGNED(v24, 424+0x180) | |
| 689 | SAVE_VECTOR_UNALIGNED(v25, 424+0x190) | |
| 690 | SAVE_VECTOR_UNALIGNED(v26, 424+0x1A0) | |
| 691 | SAVE_VECTOR_UNALIGNED(v27, 424+0x1B0) | |
| 692 | SAVE_VECTOR_UNALIGNED(v28, 424+0x1C0) | |
| 693 | SAVE_VECTOR_UNALIGNED(v29, 424+0x1D0) | |
| 694 | SAVE_VECTOR_UNALIGNED(v30, 424+0x1E0) | |
| 695 | SAVE_VECTOR_UNALIGNED(v31, 424+0x1F0) | |
| 696 | ||
| 697 | li r3, 0 ; return UNW_ESUCCESS | |
| 698 | blr | |
| 699 | ||
| 700 | ||
| 701 | #elif defined(__arm64__) || defined(__aarch64__) | |
| 702 | ||
| 703 | // | |
| 704 | // extern int unw_getcontext(unw_context_t* thread_state) | |
| 705 | // | |
| 706 | // On entry: | |
| 707 | // thread_state pointer is in x0 | |
| 708 | // | |
| 709 | .p2align 2 | |
| 710 | DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) | |
| 711 | stp x0, x1, [x0, #0x000] | |
| 712 | stp x2, x3, [x0, #0x010] | |
| 713 | stp x4, x5, [x0, #0x020] | |
| 714 | stp x6, x7, [x0, #0x030] | |
| 715 | stp x8, x9, [x0, #0x040] | |
| 716 | stp x10,x11, [x0, #0x050] | |
| 717 | stp x12,x13, [x0, #0x060] | |
| 718 | stp x14,x15, [x0, #0x070] | |
| 719 | stp x16,x17, [x0, #0x080] | |
| 720 | stp x18,x19, [x0, #0x090] | |
| 721 | stp x20,x21, [x0, #0x0A0] | |
| 722 | stp x22,x23, [x0, #0x0B0] | |
| 723 | stp x24,x25, [x0, #0x0C0] | |
| 724 | stp x26,x27, [x0, #0x0D0] | |
| 725 | stp x28,x29, [x0, #0x0E0] | |
| 726 | str x30, [x0, #0x0F0] | |
| 727 | mov x1,sp | |
| 728 | str x1, [x0, #0x0F8] | |
| 729 | str x30, [x0, #0x100] // store return address as pc | |
| 730 | // skip cpsr | |
| 731 | stp d0, d1, [x0, #0x110] | |
| 732 | stp d2, d3, [x0, #0x120] | |
| 733 | stp d4, d5, [x0, #0x130] | |
| 734 | stp d6, d7, [x0, #0x140] | |
| 735 | stp d8, d9, [x0, #0x150] | |
| 736 | stp d10,d11, [x0, #0x160] | |
| 737 | stp d12,d13, [x0, #0x170] | |
| 738 | stp d14,d15, [x0, #0x180] | |
| 739 | stp d16,d17, [x0, #0x190] | |
| 740 | stp d18,d19, [x0, #0x1A0] | |
| 741 | stp d20,d21, [x0, #0x1B0] | |
| 742 | stp d22,d23, [x0, #0x1C0] | |
| 743 | stp d24,d25, [x0, #0x1D0] | |
| 744 | stp d26,d27, [x0, #0x1E0] | |
| 745 | stp d28,d29, [x0, #0x1F0] | |
| 746 | str d30, [x0, #0x200] | |
| 747 | str d31, [x0, #0x208] | |
| 748 | mov x0, #0 // return UNW_ESUCCESS | |
| 749 | ret | |
| 750 | ||
| 751 | #elif defined(__arm__) && !defined(__APPLE__) | |
| 752 | ||
| 753 | #if !defined(__ARM_ARCH_ISA_ARM) | |
| 754 | .thumb | |
| 755 | #endif | |
| 756 | ||
| 757 | @ | |
| 758 | @ extern int unw_getcontext(unw_context_t* thread_state) | |
| 759 | @ | |
| 760 | @ On entry: | |
| 761 | @ thread_state pointer is in r0 | |
| 762 | @ | |
| 763 | @ Per EHABI #4.7 this only saves the core integer registers. | |
| 764 | @ EHABI #7.4.5 notes that in general all VRS registers should be restored | |
| 765 | @ however this is very hard to do for VFP registers because it is unknown | |
| 766 | @ to the library how many registers are implemented by the architecture. | |
| 767 | @ Instead, VFP registers are demand saved by logic external to unw_getcontext. | |
| 768 | @ | |
| 769 | .p2align 2 | |
| 770 | DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) | |
| 771 | #if !defined(__ARM_ARCH_ISA_ARM) && __ARM_ARCH_ISA_THUMB == 1 | |
| 772 | stm r0!, {r0-r7} | |
| 773 | mov r1, r8 | |
| 774 | mov r2, r9 | |
| 775 | mov r3, r10 | |
| 776 | stm r0!, {r1-r3} | |
| 777 | mov r1, r11 | |
| 778 | mov r2, sp | |
| 779 | mov r3, lr | |
| 780 | str r1, [r0, #0] @ r11 | |
| 781 | @ r12 does not need storing, it it the intra-procedure-call scratch register | |
| 782 | str r2, [r0, #8] @ sp | |
| 783 | str r3, [r0, #12] @ lr | |
| 784 | str r3, [r0, #16] @ store return address as pc | |
| 785 | @ T1 does not have a non-cpsr-clobbering register-zeroing instruction. | |
| 786 | @ It is safe to use here though because we are about to return, and cpsr is | |
| 787 | @ not expected to be preserved. | |
| 788 | movs r0, #0 @ return UNW_ESUCCESS | |
| 789 | #else | |
| 790 | @ 32bit thumb-2 restrictions for stm: | |
| 791 | @ . the sp (r13) cannot be in the list | |
| 792 | @ . the pc (r15) cannot be in the list in an STM instruction | |
| 793 | stm r0, {r0-r12} | |
| 794 | str sp, [r0, #52] | |
| 795 | str lr, [r0, #56] | |
| 796 | str lr, [r0, #60] @ store return address as pc | |
| 797 | mov r0, #0 @ return UNW_ESUCCESS | |
| 798 | #endif | |
| 799 | JMP(lr) | |
| 800 | ||
| 801 | @ | |
| 802 | @ static void libunwind::Registers_arm::saveVFPWithFSTMD(unw_fpreg_t* values) | |
| 803 | @ | |
| 804 | @ On entry: | |
| 805 | @ values pointer is in r0 | |
| 806 | @ | |
| 807 | .p2align 2 | |
| 808 | #if defined(__ELF__) | |
| 809 | .fpu vfpv3-d16 | |
| 810 | #endif | |
| 811 | DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMDEPy) | |
| 812 | vstmia r0, {d0-d15} | |
| 813 | JMP(lr) | |
| 814 | ||
| 815 | @ | |
| 816 | @ static void libunwind::Registers_arm::saveVFPWithFSTMX(unw_fpreg_t* values) | |
| 817 | @ | |
| 818 | @ On entry: | |
| 819 | @ values pointer is in r0 | |
| 820 | @ | |
| 821 | .p2align 2 | |
| 822 | #if defined(__ELF__) | |
| 823 | .fpu vfpv3-d16 | |
| 824 | #endif | |
| 825 | DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMXEPy) | |
| 826 | vstmia r0, {d0-d15} @ fstmiax is deprecated in ARMv7+ and now behaves like vstmia | |
| 827 | JMP(lr) | |
| 828 | ||
| 829 | @ | |
| 830 | @ static void libunwind::Registers_arm::saveVFPv3(unw_fpreg_t* values) | |
| 831 | @ | |
| 832 | @ On entry: | |
| 833 | @ values pointer is in r0 | |
| 834 | @ | |
| 835 | .p2align 2 | |
| 836 | #if defined(__ELF__) | |
| 837 | .fpu vfpv3 | |
| 838 | #endif | |
| 839 | DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveVFPv3EPy) | |
| 840 | @ VFP and iwMMX instructions are only available when compiling with the flags | |
| 841 | @ that enable them. We do not want to do that in the library (because we do not | |
| 842 | @ want the compiler to generate instructions that access those) but this is | |
| 843 | @ only accessed if the personality routine needs these registers. Use of | |
| 844 | @ these registers implies they are, actually, available on the target, so | |
| 845 | @ it's ok to execute. | |
| 846 | @ So, generate the instructions using the corresponding coprocessor mnemonic. | |
| 847 | vstmia r0, {d16-d31} | |
| 848 | JMP(lr) | |
| 849 | ||
| 850 | #if defined(_LIBUNWIND_ARM_WMMX) | |
| 851 | ||
| 852 | @ | |
| 853 | @ static void libunwind::Registers_arm::saveiWMMX(unw_fpreg_t* values) | |
| 854 | @ | |
| 855 | @ On entry: | |
| 856 | @ values pointer is in r0 | |
| 857 | @ | |
| 858 | .p2align 2 | |
| 859 | #if defined(__ELF__) | |
| 860 | .arch armv5te | |
| 861 | #endif | |
| 862 | DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveiWMMXEPy) | |
| 863 | stcl p1, cr0, [r0], #8 @ wstrd wR0, [r0], #8 | |
| 864 | stcl p1, cr1, [r0], #8 @ wstrd wR1, [r0], #8 | |
| 865 | stcl p1, cr2, [r0], #8 @ wstrd wR2, [r0], #8 | |
| 866 | stcl p1, cr3, [r0], #8 @ wstrd wR3, [r0], #8 | |
| 867 | stcl p1, cr4, [r0], #8 @ wstrd wR4, [r0], #8 | |
| 868 | stcl p1, cr5, [r0], #8 @ wstrd wR5, [r0], #8 | |
| 869 | stcl p1, cr6, [r0], #8 @ wstrd wR6, [r0], #8 | |
| 870 | stcl p1, cr7, [r0], #8 @ wstrd wR7, [r0], #8 | |
| 871 | stcl p1, cr8, [r0], #8 @ wstrd wR8, [r0], #8 | |
| 872 | stcl p1, cr9, [r0], #8 @ wstrd wR9, [r0], #8 | |
| 873 | stcl p1, cr10, [r0], #8 @ wstrd wR10, [r0], #8 | |
| 874 | stcl p1, cr11, [r0], #8 @ wstrd wR11, [r0], #8 | |
| 875 | stcl p1, cr12, [r0], #8 @ wstrd wR12, [r0], #8 | |
| 876 | stcl p1, cr13, [r0], #8 @ wstrd wR13, [r0], #8 | |
| 877 | stcl p1, cr14, [r0], #8 @ wstrd wR14, [r0], #8 | |
| 878 | stcl p1, cr15, [r0], #8 @ wstrd wR15, [r0], #8 | |
| 879 | JMP(lr) | |
| 880 | ||
| 881 | @ | |
| 882 | @ static void libunwind::Registers_arm::saveiWMMXControl(unw_uint32_t* values) | |
| 883 | @ | |
| 884 | @ On entry: | |
| 885 | @ values pointer is in r0 | |
| 886 | @ | |
| 887 | .p2align 2 | |
| 888 | #if defined(__ELF__) | |
| 889 | .arch armv5te | |
| 890 | #endif | |
| 891 | DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveiWMMXControlEPj) | |
| 892 | stc2 p1, cr8, [r0], #4 @ wstrw wCGR0, [r0], #4 | |
| 893 | stc2 p1, cr9, [r0], #4 @ wstrw wCGR1, [r0], #4 | |
| 894 | stc2 p1, cr10, [r0], #4 @ wstrw wCGR2, [r0], #4 | |
| 895 | stc2 p1, cr11, [r0], #4 @ wstrw wCGR3, [r0], #4 | |
| 896 | JMP(lr) | |
| 897 | ||
| 898 | #endif | |
| 899 | ||
| 900 | #elif defined(__or1k__) | |
| 901 | ||
| 902 | # | |
| 903 | # extern int unw_getcontext(unw_context_t* thread_state) | |
| 904 | # | |
| 905 | # On entry: | |
| 906 | # thread_state pointer is in r3 | |
| 907 | # | |
| 908 | DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) | |
| 909 | l.sw 0(r3), r0 | |
| 910 | l.sw 4(r3), r1 | |
| 911 | l.sw 8(r3), r2 | |
| 912 | l.sw 12(r3), r3 | |
| 913 | l.sw 16(r3), r4 | |
| 914 | l.sw 20(r3), r5 | |
| 915 | l.sw 24(r3), r6 | |
| 916 | l.sw 28(r3), r7 | |
| 917 | l.sw 32(r3), r8 | |
| 918 | l.sw 36(r3), r9 | |
| 919 | l.sw 40(r3), r10 | |
| 920 | l.sw 44(r3), r11 | |
| 921 | l.sw 48(r3), r12 | |
| 922 | l.sw 52(r3), r13 | |
| 923 | l.sw 56(r3), r14 | |
| 924 | l.sw 60(r3), r15 | |
| 925 | l.sw 64(r3), r16 | |
| 926 | l.sw 68(r3), r17 | |
| 927 | l.sw 72(r3), r18 | |
| 928 | l.sw 76(r3), r19 | |
| 929 | l.sw 80(r3), r20 | |
| 930 | l.sw 84(r3), r21 | |
| 931 | l.sw 88(r3), r22 | |
| 932 | l.sw 92(r3), r23 | |
| 933 | l.sw 96(r3), r24 | |
| 934 | l.sw 100(r3), r25 | |
| 935 | l.sw 104(r3), r26 | |
| 936 | l.sw 108(r3), r27 | |
| 937 | l.sw 112(r3), r28 | |
| 938 | l.sw 116(r3), r29 | |
| 939 | l.sw 120(r3), r30 | |
| 940 | l.sw 124(r3), r31 | |
| 941 | # store ra to pc | |
| 942 | l.sw 128(r3), r9 | |
| 943 | # zero epcr | |
| 944 | l.sw 132(r3), r0 | |
| 945 | ||
| 946 | #elif defined(__sparc__) | |
| 947 | ||
| 948 | # | |
| 949 | # extern int unw_getcontext(unw_context_t* thread_state) | |
| 950 | # | |
| 951 | # On entry: | |
| 952 | # thread_state pointer is in o0 | |
| 953 | # | |
| 954 | DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) | |
| 955 | ta 3 | |
| 956 | add %o7, 8, %o7 | |
| 957 | std %g0, [%o0 + 0] | |
| 958 | std %g2, [%o0 + 8] | |
| 959 | std %g4, [%o0 + 16] | |
| 960 | std %g6, [%o0 + 24] | |
| 961 | std %o0, [%o0 + 32] | |
| 962 | std %o2, [%o0 + 40] | |
| 963 | std %o4, [%o0 + 48] | |
| 964 | std %o6, [%o0 + 56] | |
| 965 | std %l0, [%o0 + 64] | |
| 966 | std %l2, [%o0 + 72] | |
| 967 | std %l4, [%o0 + 80] | |
| 968 | std %l6, [%o0 + 88] | |
| 969 | std %i0, [%o0 + 96] | |
| 970 | std %i2, [%o0 + 104] | |
| 971 | std %i4, [%o0 + 112] | |
| 972 | std %i6, [%o0 + 120] | |
| 973 | jmp %o7 | |
| 974 | clr %o0 // return UNW_ESUCCESS | |
| 975 | #endif | |
| 976 | #endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */ | |
| 977 | ||
| 978 | NO_EXEC_STACK_DIRECTIVE |
libunwind/src/Unwind_AppleExtras.cpp created+184| ... | ... | @@ -0,0 +1,184 @@ |
| 1 | //===--------------------- Unwind_AppleExtras.cpp -------------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is dual licensed under the MIT and the University of Illinois Open | |
| 6 | // Source Licenses. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | // | |
| 9 | //===----------------------------------------------------------------------===// | |
| 10 | ||
| 11 | #include "config.h" | |
| 12 | #include "AddressSpace.hpp" | |
| 13 | #include "DwarfParser.hpp" | |
| 14 | ||
| 15 | ||
| 16 | // private keymgr stuff | |
| 17 | #define KEYMGR_GCC3_DW2_OBJ_LIST 302 | |
| 18 | extern "C" { | |
| 19 | extern void _keymgr_set_and_unlock_processwide_ptr(int key, void *ptr); | |
| 20 | extern void *_keymgr_get_and_lock_processwide_ptr(int key); | |
| 21 | } | |
| 22 | ||
| 23 | // undocumented libgcc "struct object" | |
| 24 | struct libgcc_object { | |
| 25 | void *start; | |
| 26 | void *unused1; | |
| 27 | void *unused2; | |
| 28 | void *fde; | |
| 29 | unsigned long encoding; | |
| 30 | void *fde_end; | |
| 31 | libgcc_object *next; | |
| 32 | }; | |
| 33 | ||
| 34 | // undocumented libgcc "struct km_object_info" referenced by | |
| 35 | // KEYMGR_GCC3_DW2_OBJ_LIST | |
| 36 | struct libgcc_object_info { | |
| 37 | libgcc_object *seen_objects; | |
| 38 | libgcc_object *unseen_objects; | |
| 39 | unsigned spare[2]; | |
| 40 | }; | |
| 41 | ||
| 42 | ||
| 43 | // static linker symbols to prevent wrong two level namespace for _Unwind symbols | |
| 44 | #if defined(__arm__) | |
| 45 | #define NOT_HERE_BEFORE_5_0(sym) \ | |
| 46 | extern const char sym##_tmp30 __asm("$ld$hide$os3.0$_" #sym ); \ | |
| 47 | __attribute__((visibility("default"))) const char sym##_tmp30 = 0; \ | |
| 48 | extern const char sym##_tmp31 __asm("$ld$hide$os3.1$_" #sym ); \ | |
| 49 | __attribute__((visibility("default"))) const char sym##_tmp31 = 0; \ | |
| 50 | extern const char sym##_tmp32 __asm("$ld$hide$os3.2$_" #sym );\ | |
| 51 | __attribute__((visibility("default"))) const char sym##_tmp32 = 0; \ | |
| 52 | extern const char sym##_tmp40 __asm("$ld$hide$os4.0$_" #sym ); \ | |
| 53 | __attribute__((visibility("default"))) const char sym##_tmp40 = 0; \ | |
| 54 | extern const char sym##_tmp41 __asm("$ld$hide$os4.1$_" #sym ); \ | |
| 55 | __attribute__((visibility("default"))) const char sym##_tmp41 = 0; \ | |
| 56 | extern const char sym##_tmp42 __asm("$ld$hide$os4.2$_" #sym ); \ | |
| 57 | __attribute__((visibility("default"))) const char sym##_tmp42 = 0; \ | |
| 58 | extern const char sym##_tmp43 __asm("$ld$hide$os4.3$_" #sym ); \ | |
| 59 | __attribute__((visibility("default"))) const char sym##_tmp43 = 0; | |
| 60 | #elif defined(__arm64__) | |
| 61 | #define NOT_HERE_BEFORE_10_6(sym) | |
| 62 | #define NEVER_HERE(sym) | |
| 63 | #else | |
| 64 | #define NOT_HERE_BEFORE_10_6(sym) \ | |
| 65 | extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \ | |
| 66 | __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \ | |
| 67 | extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \ | |
| 68 | __attribute__((visibility("default"))) const char sym##_tmp5 = 0; | |
| 69 | #define NEVER_HERE(sym) \ | |
| 70 | extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \ | |
| 71 | __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \ | |
| 72 | extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \ | |
| 73 | __attribute__((visibility("default"))) const char sym##_tmp5 = 0; \ | |
| 74 | extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym ); \ | |
| 75 | __attribute__((visibility("default"))) const char sym##_tmp6 = 0; | |
| 76 | #endif | |
| 77 | ||
| 78 | ||
| 79 | #if defined(_LIBUNWIND_BUILD_ZERO_COST_APIS) | |
| 80 | ||
| 81 | // | |
| 82 | // symbols in libSystem.dylib in 10.6 and later, but are in libgcc_s.dylib in | |
| 83 | // earlier versions | |
| 84 | // | |
| 85 | NOT_HERE_BEFORE_10_6(_Unwind_DeleteException) | |
| 86 | NOT_HERE_BEFORE_10_6(_Unwind_Find_FDE) | |
| 87 | NOT_HERE_BEFORE_10_6(_Unwind_ForcedUnwind) | |
| 88 | NOT_HERE_BEFORE_10_6(_Unwind_GetGR) | |
| 89 | NOT_HERE_BEFORE_10_6(_Unwind_GetIP) | |
| 90 | NOT_HERE_BEFORE_10_6(_Unwind_GetLanguageSpecificData) | |
| 91 | NOT_HERE_BEFORE_10_6(_Unwind_GetRegionStart) | |
| 92 | NOT_HERE_BEFORE_10_6(_Unwind_RaiseException) | |
| 93 | NOT_HERE_BEFORE_10_6(_Unwind_Resume) | |
| 94 | NOT_HERE_BEFORE_10_6(_Unwind_SetGR) | |
| 95 | NOT_HERE_BEFORE_10_6(_Unwind_SetIP) | |
| 96 | NOT_HERE_BEFORE_10_6(_Unwind_Backtrace) | |
| 97 | NOT_HERE_BEFORE_10_6(_Unwind_FindEnclosingFunction) | |
| 98 | NOT_HERE_BEFORE_10_6(_Unwind_GetCFA) | |
| 99 | NOT_HERE_BEFORE_10_6(_Unwind_GetDataRelBase) | |
| 100 | NOT_HERE_BEFORE_10_6(_Unwind_GetTextRelBase) | |
| 101 | NOT_HERE_BEFORE_10_6(_Unwind_Resume_or_Rethrow) | |
| 102 | NOT_HERE_BEFORE_10_6(_Unwind_GetIPInfo) | |
| 103 | NOT_HERE_BEFORE_10_6(__register_frame) | |
| 104 | NOT_HERE_BEFORE_10_6(__deregister_frame) | |
| 105 | ||
| 106 | // | |
| 107 | // symbols in libSystem.dylib for compatibility, but we don't want any new code | |
| 108 | // using them | |
| 109 | // | |
| 110 | NEVER_HERE(__register_frame_info_bases) | |
| 111 | NEVER_HERE(__register_frame_info) | |
| 112 | NEVER_HERE(__register_frame_info_table_bases) | |
| 113 | NEVER_HERE(__register_frame_info_table) | |
| 114 | NEVER_HERE(__register_frame_table) | |
| 115 | NEVER_HERE(__deregister_frame_info) | |
| 116 | NEVER_HERE(__deregister_frame_info_bases) | |
| 117 | ||
| 118 | #endif // defined(_LIBUNWIND_BUILD_ZERO_COST_APIS) | |
| 119 | ||
| 120 | ||
| 121 | ||
| 122 | ||
| 123 | #if defined(_LIBUNWIND_BUILD_SJLJ_APIS) | |
| 124 | // | |
| 125 | // symbols in libSystem.dylib in iOS 5.0 and later, but are in libgcc_s.dylib in | |
| 126 | // earlier versions | |
| 127 | // | |
| 128 | NOT_HERE_BEFORE_5_0(_Unwind_GetLanguageSpecificData) | |
| 129 | NOT_HERE_BEFORE_5_0(_Unwind_GetRegionStart) | |
| 130 | NOT_HERE_BEFORE_5_0(_Unwind_GetIP) | |
| 131 | NOT_HERE_BEFORE_5_0(_Unwind_SetGR) | |
| 132 | NOT_HERE_BEFORE_5_0(_Unwind_SetIP) | |
| 133 | NOT_HERE_BEFORE_5_0(_Unwind_DeleteException) | |
| 134 | NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Register) | |
| 135 | NOT_HERE_BEFORE_5_0(_Unwind_GetGR) | |
| 136 | NOT_HERE_BEFORE_5_0(_Unwind_GetIPInfo) | |
| 137 | NOT_HERE_BEFORE_5_0(_Unwind_GetCFA) | |
| 138 | NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Resume) | |
| 139 | NOT_HERE_BEFORE_5_0(_Unwind_SjLj_RaiseException) | |
| 140 | NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Resume_or_Rethrow) | |
| 141 | NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Unregister) | |
| 142 | ||
| 143 | #endif // defined(_LIBUNWIND_BUILD_SJLJ_APIS) | |
| 144 | ||
| 145 | ||
| 146 | namespace libunwind { | |
| 147 | ||
| 148 | _LIBUNWIND_HIDDEN | |
| 149 | bool checkKeyMgrRegisteredFDEs(uintptr_t pc, void *&fde) { | |
| 150 | #if __MAC_OS_X_VERSION_MIN_REQUIRED | |
| 151 | // lastly check for old style keymgr registration of dynamically generated | |
| 152 | // FDEs acquire exclusive access to libgcc_object_info | |
| 153 | libgcc_object_info *head = (libgcc_object_info *) | |
| 154 | _keymgr_get_and_lock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST); | |
| 155 | if (head != NULL) { | |
| 156 | // look at each FDE in keymgr | |
| 157 | for (libgcc_object *ob = head->unseen_objects; ob != NULL; ob = ob->next) { | |
| 158 | CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo; | |
| 159 | CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo; | |
| 160 | const char *msg = CFI_Parser<LocalAddressSpace>::decodeFDE( | |
| 161 | LocalAddressSpace::sThisAddressSpace, | |
| 162 | (uintptr_t)ob->fde, &fdeInfo, &cieInfo); | |
| 163 | if (msg == NULL) { | |
| 164 | // Check if this FDE is for a function that includes the pc | |
| 165 | if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd)) { | |
| 166 | fde = (void*)fdeInfo.pcStart; | |
| 167 | _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, | |
| 168 | head); | |
| 169 | return true; | |
| 170 | } | |
| 171 | } | |
| 172 | } | |
| 173 | } | |
| 174 | // release libgcc_object_info | |
| 175 | _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, head); | |
| 176 | #else | |
| 177 | (void)pc; | |
| 178 | (void)fde; | |
| 179 | #endif | |
| 180 | return false; | |
| 181 | } | |
| 182 | ||
| 183 | } | |
| 184 |
libunwind/src/assembly.h created+124| ... | ... | @@ -0,0 +1,124 @@ |
| 1 | /* ===-- assembly.h - libUnwind assembler support macros -------------------=== | |
| 2 | * | |
| 3 | * The LLVM Compiler Infrastructure | |
| 4 | * | |
| 5 | * This file is dual licensed under the MIT and the University of Illinois Open | |
| 6 | * Source Licenses. See LICENSE.TXT for details. | |
| 7 | * | |
| 8 | * ===----------------------------------------------------------------------=== | |
| 9 | * | |
| 10 | * This file defines macros for use in libUnwind assembler source. | |
| 11 | * This file is not part of the interface of this library. | |
| 12 | * | |
| 13 | * ===----------------------------------------------------------------------=== | |
| 14 | */ | |
| 15 | ||
| 16 | #ifndef UNWIND_ASSEMBLY_H | |
| 17 | #define UNWIND_ASSEMBLY_H | |
| 18 | ||
| 19 | #if defined(__powerpc64__) | |
| 20 | #define SEPARATOR ; | |
| 21 | #define PPC64_OFFS_SRR0 0 | |
| 22 | #define PPC64_OFFS_CR 272 | |
| 23 | #define PPC64_OFFS_XER 280 | |
| 24 | #define PPC64_OFFS_LR 288 | |
| 25 | #define PPC64_OFFS_CTR 296 | |
| 26 | #define PPC64_OFFS_VRSAVE 304 | |
| 27 | #define PPC64_OFFS_FP 312 | |
| 28 | #define PPC64_OFFS_V 824 | |
| 29 | #ifdef _ARCH_PWR8 | |
| 30 | #define PPC64_HAS_VMX | |
| 31 | #endif | |
| 32 | #elif defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__) | |
| 33 | #define SEPARATOR @ | |
| 34 | #elif defined(__arm64__) | |
| 35 | #define SEPARATOR %% | |
| 36 | #else | |
| 37 | #define SEPARATOR ; | |
| 38 | #endif | |
| 39 | ||
| 40 | #define GLUE2(a, b) a ## b | |
| 41 | #define GLUE(a, b) GLUE2(a, b) | |
| 42 | #define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name) | |
| 43 | ||
| 44 | #if defined(__APPLE__) | |
| 45 | ||
| 46 | #define SYMBOL_IS_FUNC(name) | |
| 47 | #define EXPORT_SYMBOL(name) | |
| 48 | #define HIDDEN_SYMBOL(name) .private_extern name | |
| 49 | #define NO_EXEC_STACK_DIRECTIVE | |
| 50 | ||
| 51 | #elif defined(__ELF__) | |
| 52 | ||
| 53 | #if defined(__arm__) | |
| 54 | #define SYMBOL_IS_FUNC(name) .type name,%function | |
| 55 | #else | |
| 56 | #define SYMBOL_IS_FUNC(name) .type name,@function | |
| 57 | #endif | |
| 58 | #define EXPORT_SYMBOL(name) | |
| 59 | #define HIDDEN_SYMBOL(name) .hidden name | |
| 60 | ||
| 61 | #if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \ | |
| 62 | defined(__linux__) | |
| 63 | #define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits | |
| 64 | #else | |
| 65 | #define NO_EXEC_STACK_DIRECTIVE | |
| 66 | #endif | |
| 67 | ||
| 68 | #elif defined(_WIN32) | |
| 69 | ||
| 70 | #define SYMBOL_IS_FUNC(name) \ | |
| 71 | .def name SEPARATOR \ | |
| 72 | .scl 2 SEPARATOR \ | |
| 73 | .type 32 SEPARATOR \ | |
| 74 | .endef | |
| 75 | #define EXPORT_SYMBOL2(name) \ | |
| 76 | .section .drectve,"yn" SEPARATOR \ | |
| 77 | .ascii "-export:", #name, "\0" SEPARATOR \ | |
| 78 | .text | |
| 79 | #if defined(_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS) | |
| 80 | #define EXPORT_SYMBOL(name) | |
| 81 | #else | |
| 82 | #define EXPORT_SYMBOL(name) EXPORT_SYMBOL2(name) | |
| 83 | #endif | |
| 84 | #define HIDDEN_SYMBOL(name) | |
| 85 | ||
| 86 | #define NO_EXEC_STACK_DIRECTIVE | |
| 87 | ||
| 88 | #elif defined(__sparc__) | |
| 89 | ||
| 90 | #else | |
| 91 | ||
| 92 | #error Unsupported target | |
| 93 | ||
| 94 | #endif | |
| 95 | ||
| 96 | #define DEFINE_LIBUNWIND_FUNCTION(name) \ | |
| 97 | .globl SYMBOL_NAME(name) SEPARATOR \ | |
| 98 | EXPORT_SYMBOL(name) SEPARATOR \ | |
| 99 | SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ | |
| 100 | SYMBOL_NAME(name): | |
| 101 | ||
| 102 | #define DEFINE_LIBUNWIND_PRIVATE_FUNCTION(name) \ | |
| 103 | .globl SYMBOL_NAME(name) SEPARATOR \ | |
| 104 | HIDDEN_SYMBOL(SYMBOL_NAME(name)) SEPARATOR \ | |
| 105 | SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ | |
| 106 | SYMBOL_NAME(name): | |
| 107 | ||
| 108 | #if defined(__arm__) | |
| 109 | #if !defined(__ARM_ARCH) | |
| 110 | #define __ARM_ARCH 4 | |
| 111 | #endif | |
| 112 | ||
| 113 | #if defined(__ARM_ARCH_4T__) || __ARM_ARCH >= 5 | |
| 114 | #define ARM_HAS_BX | |
| 115 | #endif | |
| 116 | ||
| 117 | #ifdef ARM_HAS_BX | |
| 118 | #define JMP(r) bx r | |
| 119 | #else | |
| 120 | #define JMP(r) mov pc, r | |
| 121 | #endif | |
| 122 | #endif /* __arm__ */ | |
| 123 | ||
| 124 | #endif /* UNWIND_ASSEMBLY_H */ |
libunwind/src/config.h created+183| ... | ... | @@ -0,0 +1,183 @@ |
| 1 | //===----------------------------- config.h -------------------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is dual licensed under the MIT and the University of Illinois Open | |
| 6 | // Source Licenses. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | // | |
| 9 | // Defines macros used within libunwind project. | |
| 10 | // | |
| 11 | //===----------------------------------------------------------------------===// | |
| 12 | ||
| 13 | ||
| 14 | #ifndef LIBUNWIND_CONFIG_H | |
| 15 | #define LIBUNWIND_CONFIG_H | |
| 16 | ||
| 17 | #include <assert.h> | |
| 18 | #include <stdio.h> | |
| 19 | #include <stdint.h> | |
| 20 | #include <stdlib.h> | |
| 21 | ||
| 22 | // Define static_assert() unless already defined by compiler. | |
| 23 | #ifndef __has_feature | |
| 24 | #define __has_feature(__x) 0 | |
| 25 | #endif | |
| 26 | #if !(__has_feature(cxx_static_assert)) && !defined(static_assert) | |
| 27 | #define static_assert(__b, __m) \ | |
| 28 | extern int compile_time_assert_failed[ ( __b ) ? 1 : -1 ] \ | |
| 29 | __attribute__( ( unused ) ); | |
| 30 | #endif | |
| 31 | ||
| 32 | // Platform specific configuration defines. | |
| 33 | #ifdef __APPLE__ | |
| 34 | #if defined(FOR_DYLD) | |
| 35 | #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND | |
| 36 | #else | |
| 37 | #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND | |
| 38 | #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 | |
| 39 | #endif | |
| 40 | #elif defined(_WIN32) | |
| 41 | #ifdef __SEH__ | |
| 42 | #define _LIBUNWIND_SUPPORT_SEH_UNWIND 1 | |
| 43 | #else | |
| 44 | #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 | |
| 45 | #endif | |
| 46 | #else | |
| 47 | #if defined(__ARM_DWARF_EH__) || !defined(__arm__) | |
| 48 | #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 | |
| 49 | #define _LIBUNWIND_SUPPORT_DWARF_INDEX 1 | |
| 50 | #endif | |
| 51 | #endif | |
| 52 | ||
| 53 | #if defined(_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS) | |
| 54 | #define _LIBUNWIND_EXPORT | |
| 55 | #define _LIBUNWIND_HIDDEN | |
| 56 | #else | |
| 57 | #if !defined(__ELF__) && !defined(__MACH__) | |
| 58 | #define _LIBUNWIND_EXPORT __declspec(dllexport) | |
| 59 | #define _LIBUNWIND_HIDDEN | |
| 60 | #else | |
| 61 | #define _LIBUNWIND_EXPORT __attribute__((visibility("default"))) | |
| 62 | #define _LIBUNWIND_HIDDEN __attribute__((visibility("hidden"))) | |
| 63 | #endif | |
| 64 | #endif | |
| 65 | ||
| 66 | #if (defined(__APPLE__) && defined(__arm__)) || defined(__USING_SJLJ_EXCEPTIONS__) | |
| 67 | #define _LIBUNWIND_BUILD_SJLJ_APIS | |
| 68 | #endif | |
| 69 | ||
| 70 | #if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__ppc64__) || defined(__powerpc64__) | |
| 71 | #define _LIBUNWIND_SUPPORT_FRAME_APIS | |
| 72 | #endif | |
| 73 | ||
| 74 | #if defined(__i386__) || defined(__x86_64__) || \ | |
| 75 | defined(__ppc__) || defined(__ppc64__) || defined(__powerpc64__) || \ | |
| 76 | (!defined(__APPLE__) && defined(__arm__)) || \ | |
| 77 | (defined(__arm64__) || defined(__aarch64__)) || \ | |
| 78 | defined(__mips__) | |
| 79 | #if !defined(_LIBUNWIND_BUILD_SJLJ_APIS) | |
| 80 | #define _LIBUNWIND_BUILD_ZERO_COST_APIS | |
| 81 | #endif | |
| 82 | #endif | |
| 83 | ||
| 84 | #if defined(__powerpc64__) && defined(_ARCH_PWR8) | |
| 85 | #define PPC64_HAS_VMX | |
| 86 | #endif | |
| 87 | ||
| 88 | #if defined(NDEBUG) && defined(_LIBUNWIND_IS_BAREMETAL) | |
| 89 | #define _LIBUNWIND_ABORT(msg) \ | |
| 90 | do { \ | |
| 91 | abort(); \ | |
| 92 | } while (0) | |
| 93 | #else | |
| 94 | #define _LIBUNWIND_ABORT(msg) \ | |
| 95 | do { \ | |
| 96 | fprintf(stderr, "libunwind: %s %s:%d - %s\n", __func__, __FILE__, \ | |
| 97 | __LINE__, msg); \ | |
| 98 | fflush(stderr); \ | |
| 99 | abort(); \ | |
| 100 | } while (0) | |
| 101 | #endif | |
| 102 | ||
| 103 | #if defined(NDEBUG) && defined(_LIBUNWIND_IS_BAREMETAL) | |
| 104 | #define _LIBUNWIND_LOG0(msg) | |
| 105 | #define _LIBUNWIND_LOG(msg, ...) | |
| 106 | #else | |
| 107 | #define _LIBUNWIND_LOG0(msg) \ | |
| 108 | fprintf(stderr, "libunwind: " msg "\n") | |
| 109 | #define _LIBUNWIND_LOG(msg, ...) \ | |
| 110 | fprintf(stderr, "libunwind: " msg "\n", __VA_ARGS__) | |
| 111 | #endif | |
| 112 | ||
| 113 | #if defined(NDEBUG) | |
| 114 | #define _LIBUNWIND_LOG_IF_FALSE(x) x | |
| 115 | #else | |
| 116 | #define _LIBUNWIND_LOG_IF_FALSE(x) \ | |
| 117 | do { \ | |
| 118 | bool _ret = x; \ | |
| 119 | if (!_ret) \ | |
| 120 | _LIBUNWIND_LOG("" #x " failed in %s", __FUNCTION__); \ | |
| 121 | } while (0) | |
| 122 | #endif | |
| 123 | ||
| 124 | // Macros that define away in non-Debug builds | |
| 125 | #ifdef NDEBUG | |
| 126 | #define _LIBUNWIND_DEBUG_LOG(msg, ...) | |
| 127 | #define _LIBUNWIND_TRACE_API(msg, ...) | |
| 128 | #define _LIBUNWIND_TRACING_UNWINDING (0) | |
| 129 | #define _LIBUNWIND_TRACING_DWARF (0) | |
| 130 | #define _LIBUNWIND_TRACE_UNWINDING(msg, ...) | |
| 131 | #define _LIBUNWIND_TRACE_DWARF(...) | |
| 132 | #else | |
| 133 | #ifdef __cplusplus | |
| 134 | extern "C" { | |
| 135 | #endif | |
| 136 | extern bool logAPIs(); | |
| 137 | extern bool logUnwinding(); | |
| 138 | extern bool logDWARF(); | |
| 139 | #ifdef __cplusplus | |
| 140 | } | |
| 141 | #endif | |
| 142 | #define _LIBUNWIND_DEBUG_LOG(msg, ...) _LIBUNWIND_LOG(msg, __VA_ARGS__) | |
| 143 | #define _LIBUNWIND_TRACE_API(msg, ...) \ | |
| 144 | do { \ | |
| 145 | if (logAPIs()) \ | |
| 146 | _LIBUNWIND_LOG(msg, __VA_ARGS__); \ | |
| 147 | } while (0) | |
| 148 | #define _LIBUNWIND_TRACING_UNWINDING logUnwinding() | |
| 149 | #define _LIBUNWIND_TRACING_DWARF logDWARF() | |
| 150 | #define _LIBUNWIND_TRACE_UNWINDING(msg, ...) \ | |
| 151 | do { \ | |
| 152 | if (logUnwinding()) \ | |
| 153 | _LIBUNWIND_LOG(msg, __VA_ARGS__); \ | |
| 154 | } while (0) | |
| 155 | #define _LIBUNWIND_TRACE_DWARF(...) \ | |
| 156 | do { \ | |
| 157 | if (logDWARF()) \ | |
| 158 | fprintf(stderr, __VA_ARGS__); \ | |
| 159 | } while (0) | |
| 160 | #endif | |
| 161 | ||
| 162 | #ifdef __cplusplus | |
| 163 | // Used to fit UnwindCursor and Registers_xxx types against unw_context_t / | |
| 164 | // unw_cursor_t sized memory blocks. | |
| 165 | #if defined(_LIBUNWIND_IS_NATIVE_ONLY) | |
| 166 | # define COMP_OP == | |
| 167 | #else | |
| 168 | # define COMP_OP <= | |
| 169 | #endif | |
| 170 | template <typename _Type, typename _Mem> | |
| 171 | struct check_fit { | |
| 172 | template <typename T> | |
| 173 | struct blk_count { | |
| 174 | static const size_t count = | |
| 175 | (sizeof(T) + sizeof(uint64_t) - 1) / sizeof(uint64_t); | |
| 176 | }; | |
| 177 | static const bool does_fit = | |
| 178 | (blk_count<_Type>::count COMP_OP blk_count<_Mem>::count); | |
| 179 | }; | |
| 180 | #undef COMP_OP | |
| 181 | #endif // __cplusplus | |
| 182 | ||
| 183 | #endif // LIBUNWIND_CONFIG_H |
libunwind/src/dwarf2.h created+240| ... | ... | @@ -0,0 +1,240 @@ |
| 1 | //===------------------------------- dwarf2.h -----------------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is dual licensed under the MIT and the University of Illinois Open | |
| 6 | // Source Licenses. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | //===----------------------------------------------------------------------===// | |
| 9 | ||
| 10 | ||
| 11 | /* | |
| 12 | These constants were taken from version 3 of the DWARF standard, | |
| 13 | which is Copyright (c) 2005 Free Standards Group, and | |
| 14 | Copyright (c) 1992, 1993 UNIX International, Inc. | |
| 15 | */ | |
| 16 | ||
| 17 | #ifndef __DWARF2__ | |
| 18 | #define __DWARF2__ | |
| 19 | ||
| 20 | // DWARF unwind instructions | |
| 21 | enum { | |
| 22 | DW_CFA_nop = 0x0, | |
| 23 | DW_CFA_set_loc = 0x1, | |
| 24 | DW_CFA_advance_loc1 = 0x2, | |
| 25 | DW_CFA_advance_loc2 = 0x3, | |
| 26 | DW_CFA_advance_loc4 = 0x4, | |
| 27 | DW_CFA_offset_extended = 0x5, | |
| 28 | DW_CFA_restore_extended = 0x6, | |
| 29 | DW_CFA_undefined = 0x7, | |
| 30 | DW_CFA_same_value = 0x8, | |
| 31 | DW_CFA_register = 0x9, | |
| 32 | DW_CFA_remember_state = 0xA, | |
| 33 | DW_CFA_restore_state = 0xB, | |
| 34 | DW_CFA_def_cfa = 0xC, | |
| 35 | DW_CFA_def_cfa_register = 0xD, | |
| 36 | DW_CFA_def_cfa_offset = 0xE, | |
| 37 | DW_CFA_def_cfa_expression = 0xF, | |
| 38 | DW_CFA_expression = 0x10, | |
| 39 | DW_CFA_offset_extended_sf = 0x11, | |
| 40 | DW_CFA_def_cfa_sf = 0x12, | |
| 41 | DW_CFA_def_cfa_offset_sf = 0x13, | |
| 42 | DW_CFA_val_offset = 0x14, | |
| 43 | DW_CFA_val_offset_sf = 0x15, | |
| 44 | DW_CFA_val_expression = 0x16, | |
| 45 | DW_CFA_advance_loc = 0x40, // high 2 bits are 0x1, lower 6 bits are delta | |
| 46 | DW_CFA_offset = 0x80, // high 2 bits are 0x2, lower 6 bits are register | |
| 47 | DW_CFA_restore = 0xC0, // high 2 bits are 0x3, lower 6 bits are register | |
| 48 | ||
| 49 | // GNU extensions | |
| 50 | DW_CFA_GNU_window_save = 0x2D, | |
| 51 | DW_CFA_GNU_args_size = 0x2E, | |
| 52 | DW_CFA_GNU_negative_offset_extended = 0x2F, | |
| 53 | ||
| 54 | // AARCH64 extensions | |
| 55 | DW_CFA_AARCH64_negate_ra_state = 0x2D | |
| 56 | }; | |
| 57 | ||
| 58 | ||
| 59 | // FSF exception handling Pointer-Encoding constants | |
| 60 | // Used in CFI augmentation by GCC | |
| 61 | enum { | |
| 62 | DW_EH_PE_ptr = 0x00, | |
| 63 | DW_EH_PE_uleb128 = 0x01, | |
| 64 | DW_EH_PE_udata2 = 0x02, | |
| 65 | DW_EH_PE_udata4 = 0x03, | |
| 66 | DW_EH_PE_udata8 = 0x04, | |
| 67 | DW_EH_PE_signed = 0x08, | |
| 68 | DW_EH_PE_sleb128 = 0x09, | |
| 69 | DW_EH_PE_sdata2 = 0x0A, | |
| 70 | DW_EH_PE_sdata4 = 0x0B, | |
| 71 | DW_EH_PE_sdata8 = 0x0C, | |
| 72 | DW_EH_PE_absptr = 0x00, | |
| 73 | DW_EH_PE_pcrel = 0x10, | |
| 74 | DW_EH_PE_textrel = 0x20, | |
| 75 | DW_EH_PE_datarel = 0x30, | |
| 76 | DW_EH_PE_funcrel = 0x40, | |
| 77 | DW_EH_PE_aligned = 0x50, | |
| 78 | DW_EH_PE_indirect = 0x80, | |
| 79 | DW_EH_PE_omit = 0xFF | |
| 80 | }; | |
| 81 | ||
| 82 | ||
| 83 | // DWARF expressions | |
| 84 | enum { | |
| 85 | DW_OP_addr = 0x03, // constant address (size target specific) | |
| 86 | DW_OP_deref = 0x06, | |
| 87 | DW_OP_const1u = 0x08, // 1-byte constant | |
| 88 | DW_OP_const1s = 0x09, // 1-byte constant | |
| 89 | DW_OP_const2u = 0x0A, // 2-byte constant | |
| 90 | DW_OP_const2s = 0x0B, // 2-byte constant | |
| 91 | DW_OP_const4u = 0x0C, // 4-byte constant | |
| 92 | DW_OP_const4s = 0x0D, // 4-byte constant | |
| 93 | DW_OP_const8u = 0x0E, // 8-byte constant | |
| 94 | DW_OP_const8s = 0x0F, // 8-byte constant | |
| 95 | DW_OP_constu = 0x10, // ULEB128 constant | |
| 96 | DW_OP_consts = 0x11, // SLEB128 constant | |
| 97 | DW_OP_dup = 0x12, | |
| 98 | DW_OP_drop = 0x13, | |
| 99 | DW_OP_over = 0x14, | |
| 100 | DW_OP_pick = 0x15, // 1-byte stack index | |
| 101 | DW_OP_swap = 0x16, | |
| 102 | DW_OP_rot = 0x17, | |
| 103 | DW_OP_xderef = 0x18, | |
| 104 | DW_OP_abs = 0x19, | |
| 105 | DW_OP_and = 0x1A, | |
| 106 | DW_OP_div = 0x1B, | |
| 107 | DW_OP_minus = 0x1C, | |
| 108 | DW_OP_mod = 0x1D, | |
| 109 | DW_OP_mul = 0x1E, | |
| 110 | DW_OP_neg = 0x1F, | |
| 111 | DW_OP_not = 0x20, | |
| 112 | DW_OP_or = 0x21, | |
| 113 | DW_OP_plus = 0x22, | |
| 114 | DW_OP_plus_uconst = 0x23, // ULEB128 addend | |
| 115 | DW_OP_shl = 0x24, | |
| 116 | DW_OP_shr = 0x25, | |
| 117 | DW_OP_shra = 0x26, | |
| 118 | DW_OP_xor = 0x27, | |
| 119 | DW_OP_skip = 0x2F, // signed 2-byte constant | |
| 120 | DW_OP_bra = 0x28, // signed 2-byte constant | |
| 121 | DW_OP_eq = 0x29, | |
| 122 | DW_OP_ge = 0x2A, | |
| 123 | DW_OP_gt = 0x2B, | |
| 124 | DW_OP_le = 0x2C, | |
| 125 | DW_OP_lt = 0x2D, | |
| 126 | DW_OP_ne = 0x2E, | |
| 127 | DW_OP_lit0 = 0x30, // Literal 0 | |
| 128 | DW_OP_lit1 = 0x31, // Literal 1 | |
| 129 | DW_OP_lit2 = 0x32, // Literal 2 | |
| 130 | DW_OP_lit3 = 0x33, // Literal 3 | |
| 131 | DW_OP_lit4 = 0x34, // Literal 4 | |
| 132 | DW_OP_lit5 = 0x35, // Literal 5 | |
| 133 | DW_OP_lit6 = 0x36, // Literal 6 | |
| 134 | DW_OP_lit7 = 0x37, // Literal 7 | |
| 135 | DW_OP_lit8 = 0x38, // Literal 8 | |
| 136 | DW_OP_lit9 = 0x39, // Literal 9 | |
| 137 | DW_OP_lit10 = 0x3A, // Literal 10 | |
| 138 | DW_OP_lit11 = 0x3B, // Literal 11 | |
| 139 | DW_OP_lit12 = 0x3C, // Literal 12 | |
| 140 | DW_OP_lit13 = 0x3D, // Literal 13 | |
| 141 | DW_OP_lit14 = 0x3E, // Literal 14 | |
| 142 | DW_OP_lit15 = 0x3F, // Literal 15 | |
| 143 | DW_OP_lit16 = 0x40, // Literal 16 | |
| 144 | DW_OP_lit17 = 0x41, // Literal 17 | |
| 145 | DW_OP_lit18 = 0x42, // Literal 18 | |
| 146 | DW_OP_lit19 = 0x43, // Literal 19 | |
| 147 | DW_OP_lit20 = 0x44, // Literal 20 | |
| 148 | DW_OP_lit21 = 0x45, // Literal 21 | |
| 149 | DW_OP_lit22 = 0x46, // Literal 22 | |
| 150 | DW_OP_lit23 = 0x47, // Literal 23 | |
| 151 | DW_OP_lit24 = 0x48, // Literal 24 | |
| 152 | DW_OP_lit25 = 0x49, // Literal 25 | |
| 153 | DW_OP_lit26 = 0x4A, // Literal 26 | |
| 154 | DW_OP_lit27 = 0x4B, // Literal 27 | |
| 155 | DW_OP_lit28 = 0x4C, // Literal 28 | |
| 156 | DW_OP_lit29 = 0x4D, // Literal 29 | |
| 157 | DW_OP_lit30 = 0x4E, // Literal 30 | |
| 158 | DW_OP_lit31 = 0x4F, // Literal 31 | |
| 159 | DW_OP_reg0 = 0x50, // Contents of reg0 | |
| 160 | DW_OP_reg1 = 0x51, // Contents of reg1 | |
| 161 | DW_OP_reg2 = 0x52, // Contents of reg2 | |
| 162 | DW_OP_reg3 = 0x53, // Contents of reg3 | |
| 163 | DW_OP_reg4 = 0x54, // Contents of reg4 | |
| 164 | DW_OP_reg5 = 0x55, // Contents of reg5 | |
| 165 | DW_OP_reg6 = 0x56, // Contents of reg6 | |
| 166 | DW_OP_reg7 = 0x57, // Contents of reg7 | |
| 167 | DW_OP_reg8 = 0x58, // Contents of reg8 | |
| 168 | DW_OP_reg9 = 0x59, // Contents of reg9 | |
| 169 | DW_OP_reg10 = 0x5A, // Contents of reg10 | |
| 170 | DW_OP_reg11 = 0x5B, // Contents of reg11 | |
| 171 | DW_OP_reg12 = 0x5C, // Contents of reg12 | |
| 172 | DW_OP_reg13 = 0x5D, // Contents of reg13 | |
| 173 | DW_OP_reg14 = 0x5E, // Contents of reg14 | |
| 174 | DW_OP_reg15 = 0x5F, // Contents of reg15 | |
| 175 | DW_OP_reg16 = 0x60, // Contents of reg16 | |
| 176 | DW_OP_reg17 = 0x61, // Contents of reg17 | |
| 177 | DW_OP_reg18 = 0x62, // Contents of reg18 | |
| 178 | DW_OP_reg19 = 0x63, // Contents of reg19 | |
| 179 | DW_OP_reg20 = 0x64, // Contents of reg20 | |
| 180 | DW_OP_reg21 = 0x65, // Contents of reg21 | |
| 181 | DW_OP_reg22 = 0x66, // Contents of reg22 | |
| 182 | DW_OP_reg23 = 0x67, // Contents of reg23 | |
| 183 | DW_OP_reg24 = 0x68, // Contents of reg24 | |
| 184 | DW_OP_reg25 = 0x69, // Contents of reg25 | |
| 185 | DW_OP_reg26 = 0x6A, // Contents of reg26 | |
| 186 | DW_OP_reg27 = 0x6B, // Contents of reg27 | |
| 187 | DW_OP_reg28 = 0x6C, // Contents of reg28 | |
| 188 | DW_OP_reg29 = 0x6D, // Contents of reg29 | |
| 189 | DW_OP_reg30 = 0x6E, // Contents of reg30 | |
| 190 | DW_OP_reg31 = 0x6F, // Contents of reg31 | |
| 191 | DW_OP_breg0 = 0x70, // base register 0 + SLEB128 offset | |
| 192 | DW_OP_breg1 = 0x71, // base register 1 + SLEB128 offset | |
| 193 | DW_OP_breg2 = 0x72, // base register 2 + SLEB128 offset | |
| 194 | DW_OP_breg3 = 0x73, // base register 3 + SLEB128 offset | |
| 195 | DW_OP_breg4 = 0x74, // base register 4 + SLEB128 offset | |
| 196 | DW_OP_breg5 = 0x75, // base register 5 + SLEB128 offset | |
| 197 | DW_OP_breg6 = 0x76, // base register 6 + SLEB128 offset | |
| 198 | DW_OP_breg7 = 0x77, // base register 7 + SLEB128 offset | |
| 199 | DW_OP_breg8 = 0x78, // base register 8 + SLEB128 offset | |
| 200 | DW_OP_breg9 = 0x79, // base register 9 + SLEB128 offset | |
| 201 | DW_OP_breg10 = 0x7A, // base register 10 + SLEB128 offset | |
| 202 | DW_OP_breg11 = 0x7B, // base register 11 + SLEB128 offset | |
| 203 | DW_OP_breg12 = 0x7C, // base register 12 + SLEB128 offset | |
| 204 | DW_OP_breg13 = 0x7D, // base register 13 + SLEB128 offset | |
| 205 | DW_OP_breg14 = 0x7E, // base register 14 + SLEB128 offset | |
| 206 | DW_OP_breg15 = 0x7F, // base register 15 + SLEB128 offset | |
| 207 | DW_OP_breg16 = 0x80, // base register 16 + SLEB128 offset | |
| 208 | DW_OP_breg17 = 0x81, // base register 17 + SLEB128 offset | |
| 209 | DW_OP_breg18 = 0x82, // base register 18 + SLEB128 offset | |
| 210 | DW_OP_breg19 = 0x83, // base register 19 + SLEB128 offset | |
| 211 | DW_OP_breg20 = 0x84, // base register 20 + SLEB128 offset | |
| 212 | DW_OP_breg21 = 0x85, // base register 21 + SLEB128 offset | |
| 213 | DW_OP_breg22 = 0x86, // base register 22 + SLEB128 offset | |
| 214 | DW_OP_breg23 = 0x87, // base register 23 + SLEB128 offset | |
| 215 | DW_OP_breg24 = 0x88, // base register 24 + SLEB128 offset | |
| 216 | DW_OP_breg25 = 0x89, // base register 25 + SLEB128 offset | |
| 217 | DW_OP_breg26 = 0x8A, // base register 26 + SLEB128 offset | |
| 218 | DW_OP_breg27 = 0x8B, // base register 27 + SLEB128 offset | |
| 219 | DW_OP_breg28 = 0x8C, // base register 28 + SLEB128 offset | |
| 220 | DW_OP_breg29 = 0x8D, // base register 29 + SLEB128 offset | |
| 221 | DW_OP_breg30 = 0x8E, // base register 30 + SLEB128 offset | |
| 222 | DW_OP_breg31 = 0x8F, // base register 31 + SLEB128 offset | |
| 223 | DW_OP_regx = 0x90, // ULEB128 register | |
| 224 | DW_OP_fbreg = 0x91, // SLEB128 offset | |
| 225 | DW_OP_bregx = 0x92, // ULEB128 register followed by SLEB128 offset | |
| 226 | DW_OP_piece = 0x93, // ULEB128 size of piece addressed | |
| 227 | DW_OP_deref_size = 0x94, // 1-byte size of data retrieved | |
| 228 | DW_OP_xderef_size = 0x95, // 1-byte size of data retrieved | |
| 229 | DW_OP_nop = 0x96, | |
| 230 | DW_OP_push_object_addres = 0x97, | |
| 231 | DW_OP_call2 = 0x98, // 2-byte offset of DIE | |
| 232 | DW_OP_call4 = 0x99, // 4-byte offset of DIE | |
| 233 | DW_OP_call_ref = 0x9A, // 4- or 8-byte offset of DIE | |
| 234 | DW_OP_lo_user = 0xE0, | |
| 235 | DW_OP_APPLE_uninit = 0xF0, | |
| 236 | DW_OP_hi_user = 0xFF | |
| 237 | }; | |
| 238 | ||
| 239 | ||
| 240 | #endif |
libunwind/src/libunwind.cpp created+410| ... | ... | @@ -0,0 +1,410 @@ |
| 1 | //===--------------------------- libunwind.cpp ----------------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is dual licensed under the MIT and the University of Illinois Open | |
| 6 | // Source Licenses. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | // | |
| 9 | // Implements unw_* functions from <libunwind.h> | |
| 10 | // | |
| 11 | //===----------------------------------------------------------------------===// | |
| 12 | ||
| 13 | #include <libunwind.h> | |
| 14 | ||
| 15 | #ifndef NDEBUG | |
| 16 | #include <cstdlib> // getenv | |
| 17 | #endif | |
| 18 | #include <new> | |
| 19 | #include <algorithm> | |
| 20 | ||
| 21 | #include "libunwind_ext.h" | |
| 22 | #include "config.h" | |
| 23 | ||
| 24 | #include <stdlib.h> | |
| 25 | ||
| 26 | ||
| 27 | #if !defined(__USING_SJLJ_EXCEPTIONS__) | |
| 28 | #include "AddressSpace.hpp" | |
| 29 | #include "UnwindCursor.hpp" | |
| 30 | ||
| 31 | using namespace libunwind; | |
| 32 | ||
| 33 | /// internal object to represent this processes address space | |
| 34 | LocalAddressSpace LocalAddressSpace::sThisAddressSpace; | |
| 35 | ||
| 36 | _LIBUNWIND_EXPORT unw_addr_space_t unw_local_addr_space = | |
| 37 | (unw_addr_space_t)&LocalAddressSpace::sThisAddressSpace; | |
| 38 | ||
| 39 | /// record the registers and stack position of the caller | |
| 40 | extern int unw_getcontext(unw_context_t *); | |
| 41 | // note: unw_getcontext() implemented in assembly | |
| 42 | ||
| 43 | /// Create a cursor of a thread in this process given 'context' recorded by | |
| 44 | /// unw_getcontext(). | |
| 45 | _LIBUNWIND_EXPORT int unw_init_local(unw_cursor_t *cursor, | |
| 46 | unw_context_t *context) { | |
| 47 | _LIBUNWIND_TRACE_API("unw_init_local(cursor=%p, context=%p)", | |
| 48 | static_cast<void *>(cursor), | |
| 49 | static_cast<void *>(context)); | |
| 50 | #if defined(__i386__) | |
| 51 | # define REGISTER_KIND Registers_x86 | |
| 52 | #elif defined(__x86_64__) | |
| 53 | # define REGISTER_KIND Registers_x86_64 | |
| 54 | #elif defined(__powerpc64__) | |
| 55 | # define REGISTER_KIND Registers_ppc64 | |
| 56 | #elif defined(__ppc__) | |
| 57 | # define REGISTER_KIND Registers_ppc | |
| 58 | #elif defined(__aarch64__) | |
| 59 | # define REGISTER_KIND Registers_arm64 | |
| 60 | #elif defined(__arm__) | |
| 61 | # define REGISTER_KIND Registers_arm | |
| 62 | #elif defined(__or1k__) | |
| 63 | # define REGISTER_KIND Registers_or1k | |
| 64 | #elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32 | |
| 65 | # define REGISTER_KIND Registers_mips_o32 | |
| 66 | #elif defined(__mips64) | |
| 67 | # define REGISTER_KIND Registers_mips_newabi | |
| 68 | #elif defined(__mips__) | |
| 69 | # warning The MIPS architecture is not supported with this ABI and environment! | |
| 70 | #elif defined(__sparc__) | |
| 71 | # define REGISTER_KIND Registers_sparc | |
| 72 | #else | |
| 73 | # error Architecture not supported | |
| 74 | #endif | |
| 75 | // Use "placement new" to allocate UnwindCursor in the cursor buffer. | |
| 76 | new ((void *)cursor) UnwindCursor<LocalAddressSpace, REGISTER_KIND>( | |
| 77 | context, LocalAddressSpace::sThisAddressSpace); | |
| 78 | #undef REGISTER_KIND | |
| 79 | AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; | |
| 80 | co->setInfoBasedOnIPRegister(); | |
| 81 | ||
| 82 | return UNW_ESUCCESS; | |
| 83 | } | |
| 84 | ||
| 85 | #ifdef UNW_REMOTE | |
| 86 | /// Create a cursor into a thread in another process. | |
| 87 | _LIBUNWIND_EXPORT int unw_init_remote_thread(unw_cursor_t *cursor, | |
| 88 | unw_addr_space_t as, | |
| 89 | void *arg) { | |
| 90 | // special case: unw_init_remote(xx, unw_local_addr_space, xx) | |
| 91 | if (as == (unw_addr_space_t)&LocalAddressSpace::sThisAddressSpace) | |
| 92 | return unw_init_local(cursor, NULL); //FIXME | |
| 93 | ||
| 94 | // use "placement new" to allocate UnwindCursor in the cursor buffer | |
| 95 | switch (as->cpuType) { | |
| 96 | case CPU_TYPE_I386: | |
| 97 | new ((void *)cursor) | |
| 98 | UnwindCursor<RemoteAddressSpace<Pointer32<LittleEndian>>, | |
| 99 | Registers_x86>(((unw_addr_space_i386 *)as)->oas, arg); | |
| 100 | break; | |
| 101 | case CPU_TYPE_X86_64: | |
| 102 | new ((void *)cursor) | |
| 103 | UnwindCursor<RemoteAddressSpace<Pointer64<LittleEndian>>, | |
| 104 | Registers_x86_64>(((unw_addr_space_x86_64 *)as)->oas, arg); | |
| 105 | break; | |
| 106 | case CPU_TYPE_POWERPC: | |
| 107 | new ((void *)cursor) | |
| 108 | UnwindCursor<RemoteAddressSpace<Pointer32<BigEndian>>, | |
| 109 | Registers_ppc>(((unw_addr_space_ppc *)as)->oas, arg); | |
| 110 | break; | |
| 111 | default: | |
| 112 | return UNW_EUNSPEC; | |
| 113 | } | |
| 114 | return UNW_ESUCCESS; | |
| 115 | } | |
| 116 | ||
| 117 | ||
| 118 | static bool is64bit(task_t task) { | |
| 119 | return false; // FIXME | |
| 120 | } | |
| 121 | ||
| 122 | /// Create an address_space object for use in examining another task. | |
| 123 | _LIBUNWIND_EXPORT unw_addr_space_t unw_create_addr_space_for_task(task_t task) { | |
| 124 | #if __i386__ | |
| 125 | if (is64bit(task)) { | |
| 126 | unw_addr_space_x86_64 *as = new unw_addr_space_x86_64(task); | |
| 127 | as->taskPort = task; | |
| 128 | as->cpuType = CPU_TYPE_X86_64; | |
| 129 | //as->oas | |
| 130 | } else { | |
| 131 | unw_addr_space_i386 *as = new unw_addr_space_i386(task); | |
| 132 | as->taskPort = task; | |
| 133 | as->cpuType = CPU_TYPE_I386; | |
| 134 | //as->oas | |
| 135 | } | |
| 136 | #else | |
| 137 | // FIXME | |
| 138 | #endif | |
| 139 | } | |
| 140 | ||
| 141 | ||
| 142 | /// Delete an address_space object. | |
| 143 | _LIBUNWIND_EXPORT void unw_destroy_addr_space(unw_addr_space_t asp) { | |
| 144 | switch (asp->cpuType) { | |
| 145 | #if __i386__ || __x86_64__ | |
| 146 | case CPU_TYPE_I386: { | |
| 147 | unw_addr_space_i386 *as = (unw_addr_space_i386 *)asp; | |
| 148 | delete as; | |
| 149 | } | |
| 150 | break; | |
| 151 | case CPU_TYPE_X86_64: { | |
| 152 | unw_addr_space_x86_64 *as = (unw_addr_space_x86_64 *)asp; | |
| 153 | delete as; | |
| 154 | } | |
| 155 | break; | |
| 156 | #endif | |
| 157 | case CPU_TYPE_POWERPC: { | |
| 158 | unw_addr_space_ppc *as = (unw_addr_space_ppc *)asp; | |
| 159 | delete as; | |
| 160 | } | |
| 161 | break; | |
| 162 | } | |
| 163 | } | |
| 164 | #endif // UNW_REMOTE | |
| 165 | ||
| 166 | ||
| 167 | /// Get value of specified register at cursor position in stack frame. | |
| 168 | _LIBUNWIND_EXPORT int unw_get_reg(unw_cursor_t *cursor, unw_regnum_t regNum, | |
| 169 | unw_word_t *value) { | |
| 170 | _LIBUNWIND_TRACE_API("unw_get_reg(cursor=%p, regNum=%d, &value=%p)", | |
| 171 | static_cast<void *>(cursor), regNum, | |
| 172 | static_cast<void *>(value)); | |
| 173 | AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; | |
| 174 | if (co->validReg(regNum)) { | |
| 175 | *value = co->getReg(regNum); | |
| 176 | return UNW_ESUCCESS; | |
| 177 | } | |
| 178 | return UNW_EBADREG; | |
| 179 | } | |
| 180 | ||
| 181 | ||
| 182 | /// Set value of specified register at cursor position in stack frame. | |
| 183 | _LIBUNWIND_EXPORT int unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum, | |
| 184 | unw_word_t value) { | |
| 185 | _LIBUNWIND_TRACE_API("unw_set_reg(cursor=%p, regNum=%d, value=0x%" PRIxPTR ")", | |
| 186 | static_cast<void *>(cursor), regNum, value); | |
| 187 | typedef LocalAddressSpace::pint_t pint_t; | |
| 188 | AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; | |
| 189 | if (co->validReg(regNum)) { | |
| 190 | co->setReg(regNum, (pint_t)value); | |
| 191 | // specical case altering IP to re-find info (being called by personality | |
| 192 | // function) | |
| 193 | if (regNum == UNW_REG_IP) { | |
| 194 | unw_proc_info_t info; | |
| 195 | // First, get the FDE for the old location and then update it. | |
| 196 | co->getInfo(&info); | |
| 197 | co->setInfoBasedOnIPRegister(false); | |
| 198 | // If the original call expects stack adjustment, perform this now. | |
| 199 | // Normal frame unwinding would have included the offset already in the | |
| 200 | // CFA computation. | |
| 201 | // Note: for PA-RISC and other platforms where the stack grows up, | |
| 202 | // this should actually be - info.gp. LLVM doesn't currently support | |
| 203 | // any such platforms and Clang doesn't export a macro for them. | |
| 204 | if (info.gp) | |
| 205 | co->setReg(UNW_REG_SP, co->getReg(UNW_REG_SP) + info.gp); | |
| 206 | } | |
| 207 | return UNW_ESUCCESS; | |
| 208 | } | |
| 209 | return UNW_EBADREG; | |
| 210 | } | |
| 211 | ||
| 212 | ||
| 213 | /// Get value of specified float register at cursor position in stack frame. | |
| 214 | _LIBUNWIND_EXPORT int unw_get_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum, | |
| 215 | unw_fpreg_t *value) { | |
| 216 | _LIBUNWIND_TRACE_API("unw_get_fpreg(cursor=%p, regNum=%d, &value=%p)", | |
| 217 | static_cast<void *>(cursor), regNum, | |
| 218 | static_cast<void *>(value)); | |
| 219 | AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; | |
| 220 | if (co->validFloatReg(regNum)) { | |
| 221 | *value = co->getFloatReg(regNum); | |
| 222 | return UNW_ESUCCESS; | |
| 223 | } | |
| 224 | return UNW_EBADREG; | |
| 225 | } | |
| 226 | ||
| 227 | ||
| 228 | /// Set value of specified float register at cursor position in stack frame. | |
| 229 | _LIBUNWIND_EXPORT int unw_set_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum, | |
| 230 | unw_fpreg_t value) { | |
| 231 | #if defined(_LIBUNWIND_ARM_EHABI) | |
| 232 | _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%llX)", | |
| 233 | static_cast<void *>(cursor), regNum, value); | |
| 234 | #else | |
| 235 | _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%g)", | |
| 236 | static_cast<void *>(cursor), regNum, value); | |
| 237 | #endif | |
| 238 | AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; | |
| 239 | if (co->validFloatReg(regNum)) { | |
| 240 | co->setFloatReg(regNum, value); | |
| 241 | return UNW_ESUCCESS; | |
| 242 | } | |
| 243 | return UNW_EBADREG; | |
| 244 | } | |
| 245 | ||
| 246 | ||
| 247 | /// Move cursor to next frame. | |
| 248 | _LIBUNWIND_EXPORT int unw_step(unw_cursor_t *cursor) { | |
| 249 | _LIBUNWIND_TRACE_API("unw_step(cursor=%p)", static_cast<void *>(cursor)); | |
| 250 | AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; | |
| 251 | return co->step(); | |
| 252 | } | |
| 253 | ||
| 254 | ||
| 255 | /// Get unwind info at cursor position in stack frame. | |
| 256 | _LIBUNWIND_EXPORT int unw_get_proc_info(unw_cursor_t *cursor, | |
| 257 | unw_proc_info_t *info) { | |
| 258 | _LIBUNWIND_TRACE_API("unw_get_proc_info(cursor=%p, &info=%p)", | |
| 259 | static_cast<void *>(cursor), static_cast<void *>(info)); | |
| 260 | AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; | |
| 261 | co->getInfo(info); | |
| 262 | if (info->end_ip == 0) | |
| 263 | return UNW_ENOINFO; | |
| 264 | else | |
| 265 | return UNW_ESUCCESS; | |
| 266 | } | |
| 267 | ||
| 268 | ||
| 269 | /// Resume execution at cursor position (aka longjump). | |
| 270 | _LIBUNWIND_EXPORT int unw_resume(unw_cursor_t *cursor) { | |
| 271 | _LIBUNWIND_TRACE_API("unw_resume(cursor=%p)", static_cast<void *>(cursor)); | |
| 272 | AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; | |
| 273 | co->jumpto(); | |
| 274 | return UNW_EUNSPEC; | |
| 275 | } | |
| 276 | ||
| 277 | ||
| 278 | /// Get name of function at cursor position in stack frame. | |
| 279 | _LIBUNWIND_EXPORT int unw_get_proc_name(unw_cursor_t *cursor, char *buf, | |
| 280 | size_t bufLen, unw_word_t *offset) { | |
| 281 | _LIBUNWIND_TRACE_API("unw_get_proc_name(cursor=%p, &buf=%p, bufLen=%lu)", | |
| 282 | static_cast<void *>(cursor), static_cast<void *>(buf), | |
| 283 | static_cast<unsigned long>(bufLen)); | |
| 284 | AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; | |
| 285 | if (co->getFunctionName(buf, bufLen, offset)) | |
| 286 | return UNW_ESUCCESS; | |
| 287 | else | |
| 288 | return UNW_EUNSPEC; | |
| 289 | } | |
| 290 | ||
| 291 | ||
| 292 | /// Checks if a register is a floating-point register. | |
| 293 | _LIBUNWIND_EXPORT int unw_is_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum) { | |
| 294 | _LIBUNWIND_TRACE_API("unw_is_fpreg(cursor=%p, regNum=%d)", | |
| 295 | static_cast<void *>(cursor), regNum); | |
| 296 | AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; | |
| 297 | return co->validFloatReg(regNum); | |
| 298 | } | |
| 299 | ||
| 300 | ||
| 301 | /// Checks if a register is a floating-point register. | |
| 302 | _LIBUNWIND_EXPORT const char *unw_regname(unw_cursor_t *cursor, | |
| 303 | unw_regnum_t regNum) { | |
| 304 | _LIBUNWIND_TRACE_API("unw_regname(cursor=%p, regNum=%d)", | |
| 305 | static_cast<void *>(cursor), regNum); | |
| 306 | AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; | |
| 307 | return co->getRegisterName(regNum); | |
| 308 | } | |
| 309 | ||
| 310 | ||
| 311 | /// Checks if current frame is signal trampoline. | |
| 312 | _LIBUNWIND_EXPORT int unw_is_signal_frame(unw_cursor_t *cursor) { | |
| 313 | _LIBUNWIND_TRACE_API("unw_is_signal_frame(cursor=%p)", | |
| 314 | static_cast<void *>(cursor)); | |
| 315 | AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; | |
| 316 | return co->isSignalFrame(); | |
| 317 | } | |
| 318 | ||
| 319 | #ifdef __arm__ | |
| 320 | // Save VFP registers d0-d15 using FSTMIADX instead of FSTMIADD | |
| 321 | _LIBUNWIND_EXPORT void unw_save_vfp_as_X(unw_cursor_t *cursor) { | |
| 322 | _LIBUNWIND_TRACE_API("unw_fpreg_save_vfp_as_X(cursor=%p)", | |
| 323 | static_cast<void *>(cursor)); | |
| 324 | AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; | |
| 325 | return co->saveVFPAsX(); | |
| 326 | } | |
| 327 | #endif | |
| 328 | ||
| 329 | ||
| 330 | #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) | |
| 331 | /// SPI: walks cached DWARF entries | |
| 332 | _LIBUNWIND_EXPORT void unw_iterate_dwarf_unwind_cache(void (*func)( | |
| 333 | unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) { | |
| 334 | _LIBUNWIND_TRACE_API("unw_iterate_dwarf_unwind_cache(func=%p)", | |
| 335 | reinterpret_cast<void *>(func)); | |
| 336 | DwarfFDECache<LocalAddressSpace>::iterateCacheEntries(func); | |
| 337 | } | |
| 338 | ||
| 339 | ||
| 340 | /// IPI: for __register_frame() | |
| 341 | void _unw_add_dynamic_fde(unw_word_t fde) { | |
| 342 | CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo; | |
| 343 | CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo; | |
| 344 | const char *message = CFI_Parser<LocalAddressSpace>::decodeFDE( | |
| 345 | LocalAddressSpace::sThisAddressSpace, | |
| 346 | (LocalAddressSpace::pint_t) fde, &fdeInfo, &cieInfo); | |
| 347 | if (message == NULL) { | |
| 348 | // dynamically registered FDEs don't have a mach_header group they are in. | |
| 349 | // Use fde as mh_group | |
| 350 | unw_word_t mh_group = fdeInfo.fdeStart; | |
| 351 | DwarfFDECache<LocalAddressSpace>::add((LocalAddressSpace::pint_t)mh_group, | |
| 352 | fdeInfo.pcStart, fdeInfo.pcEnd, | |
| 353 | fdeInfo.fdeStart); | |
| 354 | } else { | |
| 355 | _LIBUNWIND_DEBUG_LOG("_unw_add_dynamic_fde: bad fde: %s", message); | |
| 356 | } | |
| 357 | } | |
| 358 | ||
| 359 | /// IPI: for __deregister_frame() | |
| 360 | void _unw_remove_dynamic_fde(unw_word_t fde) { | |
| 361 | // fde is own mh_group | |
| 362 | DwarfFDECache<LocalAddressSpace>::removeAllIn((LocalAddressSpace::pint_t)fde); | |
| 363 | } | |
| 364 | #endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) | |
| 365 | #endif // !defined(__USING_SJLJ_EXCEPTIONS__) | |
| 366 | ||
| 367 | ||
| 368 | ||
| 369 | // Add logging hooks in Debug builds only | |
| 370 | #ifndef NDEBUG | |
| 371 | #include <stdlib.h> | |
| 372 | ||
| 373 | _LIBUNWIND_HIDDEN | |
| 374 | bool logAPIs() { | |
| 375 | // do manual lock to avoid use of _cxa_guard_acquire or initializers | |
| 376 | static bool checked = false; | |
| 377 | static bool log = false; | |
| 378 | if (!checked) { | |
| 379 | log = (getenv("LIBUNWIND_PRINT_APIS") != NULL); | |
| 380 | checked = true; | |
| 381 | } | |
| 382 | return log; | |
| 383 | } | |
| 384 | ||
| 385 | _LIBUNWIND_HIDDEN | |
| 386 | bool logUnwinding() { | |
| 387 | // do manual lock to avoid use of _cxa_guard_acquire or initializers | |
| 388 | static bool checked = false; | |
| 389 | static bool log = false; | |
| 390 | if (!checked) { | |
| 391 | log = (getenv("LIBUNWIND_PRINT_UNWINDING") != NULL); | |
| 392 | checked = true; | |
| 393 | } | |
| 394 | return log; | |
| 395 | } | |
| 396 | ||
| 397 | _LIBUNWIND_HIDDEN | |
| 398 | bool logDWARF() { | |
| 399 | // do manual lock to avoid use of _cxa_guard_acquire or initializers | |
| 400 | static bool checked = false; | |
| 401 | static bool log = false; | |
| 402 | if (!checked) { | |
| 403 | log = (getenv("LIBUNWIND_PRINT_DWARF") != NULL); | |
| 404 | checked = true; | |
| 405 | } | |
| 406 | return log; | |
| 407 | } | |
| 408 | ||
| 409 | #endif // NDEBUG | |
| 410 |
libunwind/src/libunwind_ext.h created+47| ... | ... | @@ -0,0 +1,47 @@ |
| 1 | //===------------------------ libunwind_ext.h -----------------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is dual licensed under the MIT and the University of Illinois Open | |
| 6 | // Source Licenses. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | // | |
| 9 | // Extensions to libunwind API. | |
| 10 | // | |
| 11 | //===----------------------------------------------------------------------===// | |
| 12 | ||
| 13 | #ifndef __LIBUNWIND_EXT__ | |
| 14 | #define __LIBUNWIND_EXT__ | |
| 15 | ||
| 16 | #include "config.h" | |
| 17 | #include <libunwind.h> | |
| 18 | #include <unwind.h> | |
| 19 | ||
| 20 | #define UNW_STEP_SUCCESS 1 | |
| 21 | #define UNW_STEP_END 0 | |
| 22 | ||
| 23 | #ifdef __cplusplus | |
| 24 | extern "C" { | |
| 25 | #endif | |
| 26 | // SPI | |
| 27 | extern void unw_iterate_dwarf_unwind_cache(void (*func)(unw_word_t ip_start, | |
| 28 | unw_word_t ip_end, | |
| 29 | unw_word_t fde, | |
| 30 | unw_word_t mh)); | |
| 31 | ||
| 32 | // IPI | |
| 33 | extern void _unw_add_dynamic_fde(unw_word_t fde); | |
| 34 | extern void _unw_remove_dynamic_fde(unw_word_t fde); | |
| 35 | ||
| 36 | #if defined(_LIBUNWIND_ARM_EHABI) | |
| 37 | extern const uint32_t* decode_eht_entry(const uint32_t*, size_t*, size_t*); | |
| 38 | extern _Unwind_Reason_Code _Unwind_VRS_Interpret(_Unwind_Context *context, | |
| 39 | const uint32_t *data, | |
| 40 | size_t offset, size_t len); | |
| 41 | #endif | |
| 42 | ||
| 43 | #ifdef __cplusplus | |
| 44 | } | |
| 45 | #endif | |
| 46 | ||
| 47 | #endif // __LIBUNWIND_EXT__ |