Index: head/contrib/llvm/projects/libunwind/include/__libunwind_config.h =================================================================== --- head/contrib/llvm/projects/libunwind/include/__libunwind_config.h (revision 302449) +++ head/contrib/llvm/projects/libunwind/include/__libunwind_config.h (revision 302450) @@ -1,20 +1,63 @@ //===------------------------- __libunwind_config.h -----------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef ____LIBUNWIND_CONFIG_H__ #define ____LIBUNWIND_CONFIG_H__ #if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \ !defined(__ARM_DWARF_EH__) #define _LIBUNWIND_ARM_EHABI 1 #else #define _LIBUNWIND_ARM_EHABI 0 #endif +#if defined(_LIBUNWIND_IS_NATIVE_ONLY) +# if defined(__i386__) +# define _LIBUNWIND_TARGET_I386 1 +# define _LIBUNWIND_CONTEXT_SIZE 8 +# define _LIBUNWIND_CURSOR_SIZE 19 +# elif defined(__x86_64__) +# define _LIBUNWIND_TARGET_X86_64 1 +# define _LIBUNWIND_CONTEXT_SIZE 21 +# define _LIBUNWIND_CURSOR_SIZE 33 +# elif defined(__ppc__) +# define _LIBUNWIND_TARGET_PPC 1 +# define _LIBUNWIND_CONTEXT_SIZE 117 +# define _LIBUNWIND_CURSOR_SIZE 128 +# elif defined(__aarch64__) +# define _LIBUNWIND_TARGET_AARCH64 1 +# define _LIBUNWIND_CONTEXT_SIZE 66 +# define _LIBUNWIND_CURSOR_SIZE 78 +# elif defined(__arm__) +# define _LIBUNWIND_TARGET_ARM 1 +# define _LIBUNWIND_CONTEXT_SIZE 60 +# define _LIBUNWIND_CURSOR_SIZE 67 +# elif defined(__or1k__) +# define _LIBUNWIND_TARGET_OR1K 1 +# define _LIBUNWIND_CONTEXT_SIZE 16 +# define _LIBUNWIND_CURSOR_SIZE 28 +# elif defined(__riscv__) +# define _LIBUNWIND_TARGET_RISCV 1 +# define _LIBUNWIND_CONTEXT_SIZE 128 /* XXX */ +# define _LIBUNWIND_CURSOR_SIZE 140 /* XXX */ +# else +# error "Unsupported architecture." +# endif +#else // !_LIBUNWIND_IS_NATIVE_ONLY +# define _LIBUNWIND_TARGET_I386 1 +# define _LIBUNWIND_TARGET_X86_64 1 +# define _LIBUNWIND_TARGET_PPC 1 +# define _LIBUNWIND_TARGET_AARCH64 1 +# define _LIBUNWIND_TARGET_ARM 1 +# define _LIBUNWIND_TARGET_OR1K 1 +# define _LIBUNWIND_CONTEXT_SIZE 128 +# define _LIBUNWIND_CURSOR_SIZE 140 +#endif // _LIBUNWIND_IS_NATIVE_ONLY + #endif // ____LIBUNWIND_CONFIG_H__ Index: head/contrib/llvm/projects/libunwind/include/libunwind.h =================================================================== --- head/contrib/llvm/projects/libunwind/include/libunwind.h (revision 302449) +++ head/contrib/llvm/projects/libunwind/include/libunwind.h (revision 302450) @@ -1,607 +1,607 @@ //===---------------------------- libunwind.h -----------------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // // // Compatible with libuwind API documented at: // http://www.nongnu.org/libunwind/man/libunwind(3).html // //===----------------------------------------------------------------------===// #ifndef __LIBUNWIND__ #define __LIBUNWIND__ #include <__libunwind_config.h> #include #include #ifdef __APPLE__ #include #ifdef __arm__ #define LIBUNWIND_AVAIL __attribute__((unavailable)) #else #define LIBUNWIND_AVAIL __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_5_0) #endif #else #define LIBUNWIND_AVAIL #endif /* error codes */ enum { UNW_ESUCCESS = 0, /* no error */ UNW_EUNSPEC = -6540, /* unspecified (general) error */ UNW_ENOMEM = -6541, /* out of memory */ UNW_EBADREG = -6542, /* bad register number */ UNW_EREADONLYREG = -6543, /* attempt to write read-only register */ UNW_ESTOPUNWIND = -6544, /* stop unwinding */ UNW_EINVALIDIP = -6545, /* invalid IP */ UNW_EBADFRAME = -6546, /* bad frame */ UNW_EINVAL = -6547, /* unsupported operation or bad value */ UNW_EBADVERSION = -6548, /* unwind info has unsupported version */ UNW_ENOINFO = -6549 /* no unwind info found */ }; struct unw_context_t { - uint64_t data[128]; + uint64_t data[_LIBUNWIND_CONTEXT_SIZE]; }; typedef struct unw_context_t unw_context_t; struct unw_cursor_t { - uint64_t data[140]; + uint64_t data[_LIBUNWIND_CURSOR_SIZE]; }; typedef struct unw_cursor_t unw_cursor_t; typedef struct unw_addr_space *unw_addr_space_t; typedef int unw_regnum_t; #if _LIBUNWIND_ARM_EHABI typedef uint32_t unw_word_t; typedef uint64_t unw_fpreg_t; #else typedef uint64_t unw_word_t; typedef double unw_fpreg_t; #endif struct unw_proc_info_t { unw_word_t start_ip; /* start address of function */ unw_word_t end_ip; /* address after end of function */ unw_word_t lsda; /* address of language specific data area, */ /* or zero if not used */ unw_word_t handler; /* personality routine, or zero if not used */ unw_word_t gp; /* not used */ unw_word_t flags; /* not used */ uint32_t format; /* compact unwind encoding, or zero if none */ uint32_t unwind_info_size; /* size of dwarf unwind info, or zero if none */ unw_word_t unwind_info; /* address of dwarf unwind info, or zero */ unw_word_t extra; /* mach_header of mach-o image containing func */ }; typedef struct unw_proc_info_t unw_proc_info_t; #ifdef __cplusplus extern "C" { #endif extern int unw_getcontext(unw_context_t *) LIBUNWIND_AVAIL; extern int unw_init_local(unw_cursor_t *, unw_context_t *) LIBUNWIND_AVAIL; extern int unw_step(unw_cursor_t *) LIBUNWIND_AVAIL; extern int unw_get_reg(unw_cursor_t *, unw_regnum_t, unw_word_t *) LIBUNWIND_AVAIL; extern int unw_get_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t *) LIBUNWIND_AVAIL; extern int unw_set_reg(unw_cursor_t *, unw_regnum_t, unw_word_t) LIBUNWIND_AVAIL; extern int unw_set_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t) LIBUNWIND_AVAIL; extern int unw_resume(unw_cursor_t *) LIBUNWIND_AVAIL; #ifdef __arm__ /* Save VFP registers in FSTMX format (instead of FSTMD). */ extern void unw_save_vfp_as_X(unw_cursor_t *) LIBUNWIND_AVAIL; #endif extern const char *unw_regname(unw_cursor_t *, unw_regnum_t) LIBUNWIND_AVAIL; extern int unw_get_proc_info(unw_cursor_t *, unw_proc_info_t *) LIBUNWIND_AVAIL; extern int unw_is_fpreg(unw_cursor_t *, unw_regnum_t) LIBUNWIND_AVAIL; extern int unw_is_signal_frame(unw_cursor_t *) LIBUNWIND_AVAIL; extern int unw_get_proc_name(unw_cursor_t *, char *, size_t, unw_word_t *) LIBUNWIND_AVAIL; //extern int unw_get_save_loc(unw_cursor_t*, int, unw_save_loc_t*); extern unw_addr_space_t unw_local_addr_space; #ifdef UNW_REMOTE /* * Mac OS X "remote" API for unwinding other processes on same machine * */ extern unw_addr_space_t unw_create_addr_space_for_task(task_t); extern void unw_destroy_addr_space(unw_addr_space_t); extern int unw_init_remote_thread(unw_cursor_t *, unw_addr_space_t, thread_t *); #endif /* UNW_REMOTE */ /* * traditional libuwind "remote" API * NOT IMPLEMENTED on Mac OS X * * extern int unw_init_remote(unw_cursor_t*, unw_addr_space_t, * thread_t*); * extern unw_accessors_t unw_get_accessors(unw_addr_space_t); * extern unw_addr_space_t unw_create_addr_space(unw_accessors_t, int); * extern void unw_flush_cache(unw_addr_space_t, unw_word_t, * unw_word_t); * extern int unw_set_caching_policy(unw_addr_space_t, * unw_caching_policy_t); * extern void _U_dyn_register(unw_dyn_info_t*); * extern void _U_dyn_cancel(unw_dyn_info_t*); */ #ifdef __cplusplus } #endif // architecture independent register numbers enum { UNW_REG_IP = -1, // instruction pointer UNW_REG_SP = -2, // stack pointer }; // 32-bit x86 registers enum { UNW_X86_EAX = 0, UNW_X86_ECX = 1, UNW_X86_EDX = 2, UNW_X86_EBX = 3, UNW_X86_EBP = 4, UNW_X86_ESP = 5, UNW_X86_ESI = 6, UNW_X86_EDI = 7 }; // 64-bit x86_64 registers enum { UNW_X86_64_RAX = 0, UNW_X86_64_RDX = 1, UNW_X86_64_RCX = 2, UNW_X86_64_RBX = 3, UNW_X86_64_RSI = 4, UNW_X86_64_RDI = 5, UNW_X86_64_RBP = 6, UNW_X86_64_RSP = 7, UNW_X86_64_R8 = 8, UNW_X86_64_R9 = 9, UNW_X86_64_R10 = 10, UNW_X86_64_R11 = 11, UNW_X86_64_R12 = 12, UNW_X86_64_R13 = 13, UNW_X86_64_R14 = 14, UNW_X86_64_R15 = 15 }; // 32-bit ppc register numbers enum { UNW_PPC_R0 = 0, UNW_PPC_R1 = 1, UNW_PPC_R2 = 2, UNW_PPC_R3 = 3, UNW_PPC_R4 = 4, UNW_PPC_R5 = 5, UNW_PPC_R6 = 6, UNW_PPC_R7 = 7, UNW_PPC_R8 = 8, UNW_PPC_R9 = 9, UNW_PPC_R10 = 10, UNW_PPC_R11 = 11, UNW_PPC_R12 = 12, UNW_PPC_R13 = 13, UNW_PPC_R14 = 14, UNW_PPC_R15 = 15, UNW_PPC_R16 = 16, UNW_PPC_R17 = 17, UNW_PPC_R18 = 18, UNW_PPC_R19 = 19, UNW_PPC_R20 = 20, UNW_PPC_R21 = 21, UNW_PPC_R22 = 22, UNW_PPC_R23 = 23, UNW_PPC_R24 = 24, UNW_PPC_R25 = 25, UNW_PPC_R26 = 26, UNW_PPC_R27 = 27, UNW_PPC_R28 = 28, UNW_PPC_R29 = 29, UNW_PPC_R30 = 30, UNW_PPC_R31 = 31, UNW_PPC_F0 = 32, UNW_PPC_F1 = 33, UNW_PPC_F2 = 34, UNW_PPC_F3 = 35, UNW_PPC_F4 = 36, UNW_PPC_F5 = 37, UNW_PPC_F6 = 38, UNW_PPC_F7 = 39, UNW_PPC_F8 = 40, UNW_PPC_F9 = 41, UNW_PPC_F10 = 42, UNW_PPC_F11 = 43, UNW_PPC_F12 = 44, UNW_PPC_F13 = 45, UNW_PPC_F14 = 46, UNW_PPC_F15 = 47, UNW_PPC_F16 = 48, UNW_PPC_F17 = 49, UNW_PPC_F18 = 50, UNW_PPC_F19 = 51, UNW_PPC_F20 = 52, UNW_PPC_F21 = 53, UNW_PPC_F22 = 54, UNW_PPC_F23 = 55, UNW_PPC_F24 = 56, UNW_PPC_F25 = 57, UNW_PPC_F26 = 58, UNW_PPC_F27 = 59, UNW_PPC_F28 = 60, UNW_PPC_F29 = 61, UNW_PPC_F30 = 62, UNW_PPC_F31 = 63, UNW_PPC_MQ = 64, UNW_PPC_LR = 65, UNW_PPC_CTR = 66, UNW_PPC_AP = 67, UNW_PPC_CR0 = 68, UNW_PPC_CR1 = 69, UNW_PPC_CR2 = 70, UNW_PPC_CR3 = 71, UNW_PPC_CR4 = 72, UNW_PPC_CR5 = 73, UNW_PPC_CR6 = 74, UNW_PPC_CR7 = 75, UNW_PPC_XER = 76, UNW_PPC_V0 = 77, UNW_PPC_V1 = 78, UNW_PPC_V2 = 79, UNW_PPC_V3 = 80, UNW_PPC_V4 = 81, UNW_PPC_V5 = 82, UNW_PPC_V6 = 83, UNW_PPC_V7 = 84, UNW_PPC_V8 = 85, UNW_PPC_V9 = 86, UNW_PPC_V10 = 87, UNW_PPC_V11 = 88, UNW_PPC_V12 = 89, UNW_PPC_V13 = 90, UNW_PPC_V14 = 91, UNW_PPC_V15 = 92, UNW_PPC_V16 = 93, UNW_PPC_V17 = 94, UNW_PPC_V18 = 95, UNW_PPC_V19 = 96, UNW_PPC_V20 = 97, UNW_PPC_V21 = 98, UNW_PPC_V22 = 99, UNW_PPC_V23 = 100, UNW_PPC_V24 = 101, UNW_PPC_V25 = 102, UNW_PPC_V26 = 103, UNW_PPC_V27 = 104, UNW_PPC_V28 = 105, UNW_PPC_V29 = 106, UNW_PPC_V30 = 107, UNW_PPC_V31 = 108, UNW_PPC_VRSAVE = 109, UNW_PPC_VSCR = 110, UNW_PPC_SPE_ACC = 111, UNW_PPC_SPEFSCR = 112 }; -// 64-bit RISC-V registers -enum { - UNW_RISCV_X0 = 0, - UNW_RISCV_X1 = 1, - UNW_RISCV_RA = 1, - UNW_RISCV_X2 = 2, - UNW_RISCV_SP = 2, - UNW_RISCV_X3 = 3, - UNW_RISCV_X4 = 4, - UNW_RISCV_X5 = 5, - UNW_RISCV_X6 = 6, - UNW_RISCV_X7 = 7, - UNW_RISCV_X8 = 8, - UNW_RISCV_X9 = 9, - UNW_RISCV_X10 = 10, - UNW_RISCV_X11 = 11, - UNW_RISCV_X12 = 12, - UNW_RISCV_X13 = 13, - UNW_RISCV_X14 = 14, - UNW_RISCV_X15 = 15, - UNW_RISCV_X16 = 16, - UNW_RISCV_X17 = 17, - UNW_RISCV_X18 = 18, - UNW_RISCV_X19 = 19, - UNW_RISCV_X20 = 20, - UNW_RISCV_X21 = 21, - UNW_RISCV_X22 = 22, - UNW_RISCV_X23 = 23, - UNW_RISCV_X24 = 24, - UNW_RISCV_X25 = 25, - UNW_RISCV_X26 = 26, - UNW_RISCV_X27 = 27, - UNW_RISCV_X28 = 28, - UNW_RISCV_X29 = 29, - UNW_RISCV_X30 = 30, - UNW_RISCV_X31 = 31, - // reserved block - UNW_RISCV_D0 = 64, - UNW_RISCV_D1 = 65, - UNW_RISCV_D2 = 66, - UNW_RISCV_D3 = 67, - UNW_RISCV_D4 = 68, - UNW_RISCV_D5 = 69, - UNW_RISCV_D6 = 70, - UNW_RISCV_D7 = 71, - UNW_RISCV_D8 = 72, - UNW_RISCV_D9 = 73, - UNW_RISCV_D10 = 74, - UNW_RISCV_D11 = 75, - UNW_RISCV_D12 = 76, - UNW_RISCV_D13 = 77, - UNW_RISCV_D14 = 78, - UNW_RISCV_D15 = 79, - UNW_RISCV_D16 = 80, - UNW_RISCV_D17 = 81, - UNW_RISCV_D18 = 82, - UNW_RISCV_D19 = 83, - UNW_RISCV_D20 = 84, - UNW_RISCV_D21 = 85, - UNW_RISCV_D22 = 86, - UNW_RISCV_D23 = 87, - UNW_RISCV_D24 = 88, - UNW_RISCV_D25 = 89, - UNW_RISCV_D26 = 90, - UNW_RISCV_D27 = 91, - UNW_RISCV_D28 = 92, - UNW_RISCV_D29 = 93, - UNW_RISCV_D30 = 94, - UNW_RISCV_D31 = 95, -}; - // 64-bit ARM64 registers enum { UNW_ARM64_X0 = 0, UNW_ARM64_X1 = 1, UNW_ARM64_X2 = 2, UNW_ARM64_X3 = 3, UNW_ARM64_X4 = 4, UNW_ARM64_X5 = 5, UNW_ARM64_X6 = 6, UNW_ARM64_X7 = 7, UNW_ARM64_X8 = 8, UNW_ARM64_X9 = 9, UNW_ARM64_X10 = 10, UNW_ARM64_X11 = 11, UNW_ARM64_X12 = 12, UNW_ARM64_X13 = 13, UNW_ARM64_X14 = 14, UNW_ARM64_X15 = 15, UNW_ARM64_X16 = 16, UNW_ARM64_X17 = 17, UNW_ARM64_X18 = 18, UNW_ARM64_X19 = 19, UNW_ARM64_X20 = 20, UNW_ARM64_X21 = 21, UNW_ARM64_X22 = 22, UNW_ARM64_X23 = 23, UNW_ARM64_X24 = 24, UNW_ARM64_X25 = 25, UNW_ARM64_X26 = 26, UNW_ARM64_X27 = 27, UNW_ARM64_X28 = 28, UNW_ARM64_X29 = 29, UNW_ARM64_FP = 29, UNW_ARM64_X30 = 30, UNW_ARM64_LR = 30, UNW_ARM64_X31 = 31, UNW_ARM64_SP = 31, // reserved block UNW_ARM64_D0 = 64, UNW_ARM64_D1 = 65, UNW_ARM64_D2 = 66, UNW_ARM64_D3 = 67, UNW_ARM64_D4 = 68, UNW_ARM64_D5 = 69, UNW_ARM64_D6 = 70, UNW_ARM64_D7 = 71, UNW_ARM64_D8 = 72, UNW_ARM64_D9 = 73, UNW_ARM64_D10 = 74, UNW_ARM64_D11 = 75, UNW_ARM64_D12 = 76, UNW_ARM64_D13 = 77, UNW_ARM64_D14 = 78, UNW_ARM64_D15 = 79, UNW_ARM64_D16 = 80, UNW_ARM64_D17 = 81, UNW_ARM64_D18 = 82, UNW_ARM64_D19 = 83, UNW_ARM64_D20 = 84, UNW_ARM64_D21 = 85, UNW_ARM64_D22 = 86, UNW_ARM64_D23 = 87, UNW_ARM64_D24 = 88, UNW_ARM64_D25 = 89, UNW_ARM64_D26 = 90, UNW_ARM64_D27 = 91, UNW_ARM64_D28 = 92, UNW_ARM64_D29 = 93, UNW_ARM64_D30 = 94, UNW_ARM64_D31 = 95, }; // 32-bit ARM registers. Numbers match DWARF for ARM spec #3.1 Table 1. // Naming scheme uses recommendations given in Note 4 for VFP-v2 and VFP-v3. // In this scheme, even though the 64-bit floating point registers D0-D31 // overlap physically with the 32-bit floating pointer registers S0-S31, // they are given a non-overlapping range of register numbers. // // Commented out ranges are not preserved during unwinding. enum { UNW_ARM_R0 = 0, UNW_ARM_R1 = 1, UNW_ARM_R2 = 2, UNW_ARM_R3 = 3, UNW_ARM_R4 = 4, UNW_ARM_R5 = 5, UNW_ARM_R6 = 6, UNW_ARM_R7 = 7, UNW_ARM_R8 = 8, UNW_ARM_R9 = 9, UNW_ARM_R10 = 10, UNW_ARM_R11 = 11, UNW_ARM_R12 = 12, UNW_ARM_SP = 13, // Logical alias for UNW_REG_SP UNW_ARM_R13 = 13, UNW_ARM_LR = 14, UNW_ARM_R14 = 14, UNW_ARM_IP = 15, // Logical alias for UNW_REG_IP UNW_ARM_R15 = 15, // 16-63 -- OBSOLETE. Used in VFP1 to represent both S0-S31 and D0-D31. UNW_ARM_S0 = 64, UNW_ARM_S1 = 65, UNW_ARM_S2 = 66, UNW_ARM_S3 = 67, UNW_ARM_S4 = 68, UNW_ARM_S5 = 69, UNW_ARM_S6 = 70, UNW_ARM_S7 = 71, UNW_ARM_S8 = 72, UNW_ARM_S9 = 73, UNW_ARM_S10 = 74, UNW_ARM_S11 = 75, UNW_ARM_S12 = 76, UNW_ARM_S13 = 77, UNW_ARM_S14 = 78, UNW_ARM_S15 = 79, UNW_ARM_S16 = 80, UNW_ARM_S17 = 81, UNW_ARM_S18 = 82, UNW_ARM_S19 = 83, UNW_ARM_S20 = 84, UNW_ARM_S21 = 85, UNW_ARM_S22 = 86, UNW_ARM_S23 = 87, UNW_ARM_S24 = 88, UNW_ARM_S25 = 89, UNW_ARM_S26 = 90, UNW_ARM_S27 = 91, UNW_ARM_S28 = 92, UNW_ARM_S29 = 93, UNW_ARM_S30 = 94, UNW_ARM_S31 = 95, // 96-103 -- OBSOLETE. F0-F7. Used by the FPA system. Superseded by VFP. // 104-111 -- wCGR0-wCGR7, ACC0-ACC7 (Intel wireless MMX) UNW_ARM_WR0 = 112, UNW_ARM_WR1 = 113, UNW_ARM_WR2 = 114, UNW_ARM_WR3 = 115, UNW_ARM_WR4 = 116, UNW_ARM_WR5 = 117, UNW_ARM_WR6 = 118, UNW_ARM_WR7 = 119, UNW_ARM_WR8 = 120, UNW_ARM_WR9 = 121, UNW_ARM_WR10 = 122, UNW_ARM_WR11 = 123, UNW_ARM_WR12 = 124, UNW_ARM_WR13 = 125, UNW_ARM_WR14 = 126, UNW_ARM_WR15 = 127, // 128-133 -- SPSR, SPSR_{FIQ|IRQ|ABT|UND|SVC} // 134-143 -- Reserved // 144-150 -- R8_USR-R14_USR // 151-157 -- R8_FIQ-R14_FIQ // 158-159 -- R13_IRQ-R14_IRQ // 160-161 -- R13_ABT-R14_ABT // 162-163 -- R13_UND-R14_UND // 164-165 -- R13_SVC-R14_SVC // 166-191 -- Reserved UNW_ARM_WC0 = 192, UNW_ARM_WC1 = 193, UNW_ARM_WC2 = 194, UNW_ARM_WC3 = 195, // 196-199 -- wC4-wC7 (Intel wireless MMX control) // 200-255 -- Reserved UNW_ARM_D0 = 256, UNW_ARM_D1 = 257, UNW_ARM_D2 = 258, UNW_ARM_D3 = 259, UNW_ARM_D4 = 260, UNW_ARM_D5 = 261, UNW_ARM_D6 = 262, UNW_ARM_D7 = 263, UNW_ARM_D8 = 264, UNW_ARM_D9 = 265, UNW_ARM_D10 = 266, UNW_ARM_D11 = 267, UNW_ARM_D12 = 268, UNW_ARM_D13 = 269, UNW_ARM_D14 = 270, UNW_ARM_D15 = 271, UNW_ARM_D16 = 272, UNW_ARM_D17 = 273, UNW_ARM_D18 = 274, UNW_ARM_D19 = 275, UNW_ARM_D20 = 276, UNW_ARM_D21 = 277, UNW_ARM_D22 = 278, UNW_ARM_D23 = 279, UNW_ARM_D24 = 280, UNW_ARM_D25 = 281, UNW_ARM_D26 = 282, UNW_ARM_D27 = 283, UNW_ARM_D28 = 284, UNW_ARM_D29 = 285, UNW_ARM_D30 = 286, UNW_ARM_D31 = 287, // 288-319 -- Reserved for VFP/Neon // 320-8191 -- Reserved // 8192-16383 -- Unspecified vendor co-processor register. }; // OpenRISC1000 register numbers enum { UNW_OR1K_R0 = 0, UNW_OR1K_R1 = 1, UNW_OR1K_R2 = 2, UNW_OR1K_R3 = 3, UNW_OR1K_R4 = 4, UNW_OR1K_R5 = 5, UNW_OR1K_R6 = 6, UNW_OR1K_R7 = 7, UNW_OR1K_R8 = 8, UNW_OR1K_R9 = 9, UNW_OR1K_R10 = 10, UNW_OR1K_R11 = 11, UNW_OR1K_R12 = 12, UNW_OR1K_R13 = 13, UNW_OR1K_R14 = 14, UNW_OR1K_R15 = 15, UNW_OR1K_R16 = 16, UNW_OR1K_R17 = 17, UNW_OR1K_R18 = 18, UNW_OR1K_R19 = 19, UNW_OR1K_R20 = 20, UNW_OR1K_R21 = 21, UNW_OR1K_R22 = 22, UNW_OR1K_R23 = 23, UNW_OR1K_R24 = 24, UNW_OR1K_R25 = 25, UNW_OR1K_R26 = 26, UNW_OR1K_R27 = 27, UNW_OR1K_R28 = 28, UNW_OR1K_R29 = 29, UNW_OR1K_R30 = 30, UNW_OR1K_R31 = 31, +}; + +// 64-bit RISC-V registers +enum { + UNW_RISCV_X0 = 0, + UNW_RISCV_X1 = 1, + UNW_RISCV_RA = 1, + UNW_RISCV_X2 = 2, + UNW_RISCV_SP = 2, + UNW_RISCV_X3 = 3, + UNW_RISCV_X4 = 4, + UNW_RISCV_X5 = 5, + UNW_RISCV_X6 = 6, + UNW_RISCV_X7 = 7, + UNW_RISCV_X8 = 8, + UNW_RISCV_X9 = 9, + UNW_RISCV_X10 = 10, + UNW_RISCV_X11 = 11, + UNW_RISCV_X12 = 12, + UNW_RISCV_X13 = 13, + UNW_RISCV_X14 = 14, + UNW_RISCV_X15 = 15, + UNW_RISCV_X16 = 16, + UNW_RISCV_X17 = 17, + UNW_RISCV_X18 = 18, + UNW_RISCV_X19 = 19, + UNW_RISCV_X20 = 20, + UNW_RISCV_X21 = 21, + UNW_RISCV_X22 = 22, + UNW_RISCV_X23 = 23, + UNW_RISCV_X24 = 24, + UNW_RISCV_X25 = 25, + UNW_RISCV_X26 = 26, + UNW_RISCV_X27 = 27, + UNW_RISCV_X28 = 28, + UNW_RISCV_X29 = 29, + UNW_RISCV_X30 = 30, + UNW_RISCV_X31 = 31, + // reserved block + UNW_RISCV_D0 = 64, + UNW_RISCV_D1 = 65, + UNW_RISCV_D2 = 66, + UNW_RISCV_D3 = 67, + UNW_RISCV_D4 = 68, + UNW_RISCV_D5 = 69, + UNW_RISCV_D6 = 70, + UNW_RISCV_D7 = 71, + UNW_RISCV_D8 = 72, + UNW_RISCV_D9 = 73, + UNW_RISCV_D10 = 74, + UNW_RISCV_D11 = 75, + UNW_RISCV_D12 = 76, + UNW_RISCV_D13 = 77, + UNW_RISCV_D14 = 78, + UNW_RISCV_D15 = 79, + UNW_RISCV_D16 = 80, + UNW_RISCV_D17 = 81, + UNW_RISCV_D18 = 82, + UNW_RISCV_D19 = 83, + UNW_RISCV_D20 = 84, + UNW_RISCV_D21 = 85, + UNW_RISCV_D22 = 86, + UNW_RISCV_D23 = 87, + UNW_RISCV_D24 = 88, + UNW_RISCV_D25 = 89, + UNW_RISCV_D26 = 90, + UNW_RISCV_D27 = 91, + UNW_RISCV_D28 = 92, + UNW_RISCV_D29 = 93, + UNW_RISCV_D30 = 94, + UNW_RISCV_D31 = 95, }; #endif Index: head/contrib/llvm/projects/libunwind/src/AddressSpace.hpp =================================================================== --- head/contrib/llvm/projects/libunwind/src/AddressSpace.hpp (revision 302449) +++ head/contrib/llvm/projects/libunwind/src/AddressSpace.hpp (revision 302450) @@ -1,598 +1,599 @@ //===------------------------- AddressSpace.hpp ---------------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // // // Abstracts accessing local vs remote address spaces. // //===----------------------------------------------------------------------===// #ifndef __ADDRESSSPACE_HPP__ #define __ADDRESSSPACE_HPP__ #include #include #include #include #ifndef _LIBUNWIND_IS_BAREMETAL #include #endif #ifdef __APPLE__ #include namespace libunwind { bool checkKeyMgrRegisteredFDEs(uintptr_t targetAddr, void *&fde); } #endif #include "libunwind.h" #include "config.h" #include "dwarf2.h" #include "Registers.hpp" #if _LIBUNWIND_ARM_EHABI -#if defined(__FreeBSD__) +#if defined(__FreeBSD__) || defined(__NetBSD__) #include typedef void *_Unwind_Ptr; #elif defined(__linux__) typedef long unsigned int *_Unwind_Ptr; extern "C" _Unwind_Ptr __gnu_Unwind_Find_exidx(_Unwind_Ptr addr, int *len); // Emulate the BSD dl_unwind_find_exidx API when on a GNU libdl system. #define dl_unwind_find_exidx __gnu_Unwind_Find_exidx #elif !defined(_LIBUNWIND_IS_BAREMETAL) #include #else // !defined(_LIBUNWIND_IS_BAREMETAL) // When statically linked on bare-metal, the symbols for the EH table are looked // up without going through the dynamic loader. struct EHTEntry { uint32_t functionOffset; uint32_t unwindOpcodes; }; extern EHTEntry __exidx_start; extern EHTEntry __exidx_end; #endif // !defined(_LIBUNWIND_IS_BAREMETAL) #endif // _LIBUNWIND_ARM_EHABI -#if defined(__CloudABI__) || defined(__FreeBSD__) || defined(__linux__) +#if defined(__CloudABI__) || defined(__FreeBSD__) || defined(__linux__) || \ + defined(__NetBSD__) #if _LIBUNWIND_SUPPORT_DWARF_UNWIND && _LIBUNWIND_SUPPORT_DWARF_INDEX #include // Macro for machine-independent access to the ELF program headers. This // macro is not available on some systems (e.g., FreeBSD). On these // systems the data structures are just called Elf_XXX. Define ElfW() // locally. #if !defined(ElfW) #define ElfW(type) Elf_##type #endif #include "EHHeaderParser.hpp" #endif #endif namespace libunwind { /// Used by findUnwindSections() to return info about needed sections. struct UnwindInfoSections { #if _LIBUNWIND_SUPPORT_DWARF_UNWIND || _LIBUNWIND_SUPPORT_DWARF_INDEX || \ _LIBUNWIND_SUPPORT_COMPACT_UNWIND // No dso_base for ARM EHABI. uintptr_t dso_base; #endif #if _LIBUNWIND_SUPPORT_DWARF_UNWIND uintptr_t dwarf_section; uintptr_t dwarf_section_length; #endif #if _LIBUNWIND_SUPPORT_DWARF_INDEX uintptr_t dwarf_index_section; uintptr_t dwarf_index_section_length; #endif #if _LIBUNWIND_SUPPORT_COMPACT_UNWIND uintptr_t compact_unwind_section; uintptr_t compact_unwind_section_length; #endif #if _LIBUNWIND_ARM_EHABI uintptr_t arm_section; uintptr_t arm_section_length; #endif }; /// LocalAddressSpace is used as a template parameter to UnwindCursor when /// unwinding a thread in the same process. The wrappers compile away, /// making local unwinds fast. class __attribute__((visibility("hidden"))) LocalAddressSpace { public: #ifdef __LP64__ typedef uint64_t pint_t; typedef int64_t sint_t; #else typedef uint32_t pint_t; typedef int32_t sint_t; #endif uint8_t get8(pint_t addr) { uint8_t val; memcpy(&val, (void *)addr, sizeof(val)); return val; } uint16_t get16(pint_t addr) { uint16_t val; memcpy(&val, (void *)addr, sizeof(val)); return val; } uint32_t get32(pint_t addr) { uint32_t val; memcpy(&val, (void *)addr, sizeof(val)); return val; } uint64_t get64(pint_t addr) { uint64_t val; memcpy(&val, (void *)addr, sizeof(val)); return val; } double getDouble(pint_t addr) { double val; memcpy(&val, (void *)addr, sizeof(val)); return val; } v128 getVector(pint_t addr) { v128 val; memcpy(&val, (void *)addr, sizeof(val)); return val; } uintptr_t getP(pint_t addr); static uint64_t getULEB128(pint_t &addr, pint_t end); static int64_t getSLEB128(pint_t &addr, pint_t end); pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, pint_t datarelBase = 0); bool findFunctionName(pint_t addr, char *buf, size_t bufLen, unw_word_t *offset); bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info); bool findOtherFDE(pint_t targetAddr, pint_t &fde); static LocalAddressSpace sThisAddressSpace; }; inline uintptr_t LocalAddressSpace::getP(pint_t addr) { #ifdef __LP64__ return get64(addr); #else return get32(addr); #endif } /// Read a ULEB128 into a 64-bit word. inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) { const uint8_t *p = (uint8_t *)addr; const uint8_t *pend = (uint8_t *)end; uint64_t result = 0; int bit = 0; do { uint64_t b; if (p == pend) _LIBUNWIND_ABORT("truncated uleb128 expression"); b = *p & 0x7f; if (bit >= 64 || b << bit >> bit != b) { _LIBUNWIND_ABORT("malformed uleb128 expression"); } else { result |= b << bit; bit += 7; } } while (*p++ >= 0x80); addr = (pint_t) p; return result; } /// Read a SLEB128 into a 64-bit word. inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) { const uint8_t *p = (uint8_t *)addr; const uint8_t *pend = (uint8_t *)end; int64_t result = 0; int bit = 0; uint8_t byte; do { if (p == pend) _LIBUNWIND_ABORT("truncated sleb128 expression"); byte = *p++; result |= ((byte & 0x7f) << bit); bit += 7; } while (byte & 0x80); // sign extend negative numbers if ((byte & 0x40) != 0) result |= (-1LL) << bit; addr = (pint_t) p; return result; } inline LocalAddressSpace::pint_t LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, pint_t datarelBase) { pint_t startAddr = addr; const uint8_t *p = (uint8_t *)addr; pint_t result; // first get value switch (encoding & 0x0F) { case DW_EH_PE_ptr: result = getP(addr); p += sizeof(pint_t); addr = (pint_t) p; break; case DW_EH_PE_uleb128: result = (pint_t)getULEB128(addr, end); break; case DW_EH_PE_udata2: result = get16(addr); p += 2; addr = (pint_t) p; break; case DW_EH_PE_udata4: result = get32(addr); p += 4; addr = (pint_t) p; break; case DW_EH_PE_udata8: result = (pint_t)get64(addr); p += 8; addr = (pint_t) p; break; case DW_EH_PE_sleb128: result = (pint_t)getSLEB128(addr, end); break; case DW_EH_PE_sdata2: // Sign extend from signed 16-bit value. result = (pint_t)(int16_t)get16(addr); p += 2; addr = (pint_t) p; break; case DW_EH_PE_sdata4: // Sign extend from signed 32-bit value. result = (pint_t)(int32_t)get32(addr); p += 4; addr = (pint_t) p; break; case DW_EH_PE_sdata8: result = (pint_t)get64(addr); p += 8; addr = (pint_t) p; break; default: _LIBUNWIND_ABORT("unknown pointer encoding"); } // then add relative offset switch (encoding & 0x70) { case DW_EH_PE_absptr: // do nothing break; case DW_EH_PE_pcrel: result += startAddr; break; case DW_EH_PE_textrel: _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported"); break; case DW_EH_PE_datarel: // DW_EH_PE_datarel is only valid in a few places, so the parameter has a // default value of 0, and we abort in the event that someone calls this // function with a datarelBase of 0 and DW_EH_PE_datarel encoding. if (datarelBase == 0) _LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0"); result += datarelBase; break; case DW_EH_PE_funcrel: _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported"); break; case DW_EH_PE_aligned: _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported"); break; default: _LIBUNWIND_ABORT("unknown pointer encoding"); break; } if (encoding & DW_EH_PE_indirect) result = getP(result); return result; } #ifdef __APPLE__ struct dyld_unwind_sections { const struct mach_header* mh; const void* dwarf_section; uintptr_t dwarf_section_length; const void* compact_unwind_section; uintptr_t compact_unwind_section_length; }; #if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \ && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) \ || defined(__IPHONE_OS_VERSION_MIN_REQUIRED) // In 10.7.0 or later, libSystem.dylib implements this function. extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *); #else // In 10.6.x and earlier, we need to implement this functionality. static inline bool _dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info) { // Find mach-o image containing address. Dl_info dlinfo; if (!dladdr(addr, &dlinfo)) return false; const mach_header *mh = (const mach_header *)dlinfo.dli_saddr; // Find dwarf unwind section in that image. unsigned long size; const uint8_t *p = getsectiondata(mh, "__TEXT", "__eh_frame", &size); if (!p) return false; // Fill in return struct. info->mh = mh; info->dwarf_section = p; info->dwarf_section_length = size; info->compact_unwind_section = 0; info->compact_unwind_section_length = 0; return true; } #endif #endif inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, UnwindInfoSections &info) { #ifdef __APPLE__ dyld_unwind_sections dyldInfo; if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) { info.dso_base = (uintptr_t)dyldInfo.mh; #if _LIBUNWIND_SUPPORT_DWARF_UNWIND info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section; info.dwarf_section_length = dyldInfo.dwarf_section_length; #endif info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section; info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length; return true; } #elif _LIBUNWIND_ARM_EHABI #ifdef _LIBUNWIND_IS_BAREMETAL // Bare metal is statically linked, so no need to ask the dynamic loader info.arm_section = (uintptr_t)(&__exidx_start); info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start); #else int length = 0; info.arm_section = (uintptr_t) dl_unwind_find_exidx( (_Unwind_Ptr) targetAddr, &length); info.arm_section_length = (uintptr_t)length; #endif _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %X length %x\n", info.arm_section, info.arm_section_length); if (info.arm_section && info.arm_section_length) return true; #elif _LIBUNWIND_SUPPORT_DWARF_UNWIND #if _LIBUNWIND_SUPPORT_DWARF_INDEX struct dl_iterate_cb_data { LocalAddressSpace *addressSpace; UnwindInfoSections *sects; uintptr_t targetAddr; }; dl_iterate_cb_data cb_data = {this, &info, targetAddr}; int found = dl_iterate_phdr( [](struct dl_phdr_info *pinfo, size_t, void *data) -> int { auto cbdata = static_cast(data); size_t object_length; bool found_obj = false; bool found_hdr = false; assert(cbdata); assert(cbdata->sects); if (cbdata->targetAddr < pinfo->dlpi_addr) { return false; } #if !defined(Elf_Half) typedef ElfW(Half) Elf_Half; #endif #if !defined(Elf_Phdr) typedef ElfW(Phdr) Elf_Phdr; #endif for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) { const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i]; if (phdr->p_type == PT_LOAD) { uintptr_t begin = pinfo->dlpi_addr + phdr->p_vaddr; uintptr_t end = begin + phdr->p_memsz; if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) { cbdata->sects->dso_base = begin; object_length = phdr->p_memsz; found_obj = true; } } else if (phdr->p_type == PT_GNU_EH_FRAME) { EHHeaderParser::EHHeaderInfo hdrInfo; uintptr_t eh_frame_hdr_start = pinfo->dlpi_addr + phdr->p_vaddr; cbdata->sects->dwarf_index_section = eh_frame_hdr_start; cbdata->sects->dwarf_index_section_length = phdr->p_memsz; EHHeaderParser::decodeEHHdr( *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz, hdrInfo); cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr; found_hdr = true; } } if (found_obj && found_hdr) { cbdata->sects->dwarf_section_length = object_length; return true; } else { return false; } }, &cb_data); return static_cast(found); #else #error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform." #endif #endif return false; } inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) { #ifdef __APPLE__ return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde)); #else // TO DO: if OS has way to dynamically register FDEs, check that. (void)targetAddr; (void)fde; return false; #endif } inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf, size_t bufLen, unw_word_t *offset) { #ifndef _LIBUNWIND_IS_BAREMETAL Dl_info dyldInfo; if (dladdr((void *)addr, &dyldInfo)) { if (dyldInfo.dli_sname != NULL) { snprintf(buf, bufLen, "%s", dyldInfo.dli_sname); *offset = (addr - (pint_t) dyldInfo.dli_saddr); return true; } } #endif return false; } #ifdef UNW_REMOTE /// OtherAddressSpace is used as a template parameter to UnwindCursor when /// unwinding a thread in the another process. The other process can be a /// different endianness and a different pointer size which is handled by /// the P template parameter. template class OtherAddressSpace { public: OtherAddressSpace(task_t task) : fTask(task) {} typedef typename P::uint_t pint_t; uint8_t get8(pint_t addr); uint16_t get16(pint_t addr); uint32_t get32(pint_t addr); uint64_t get64(pint_t addr); pint_t getP(pint_t addr); uint64_t getULEB128(pint_t &addr, pint_t end); int64_t getSLEB128(pint_t &addr, pint_t end); pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, pint_t datarelBase = 0); bool findFunctionName(pint_t addr, char *buf, size_t bufLen, unw_word_t *offset); bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info); bool findOtherFDE(pint_t targetAddr, pint_t &fde); private: void *localCopy(pint_t addr); task_t fTask; }; template uint8_t OtherAddressSpace

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

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

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

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

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

::getULEB128(pint_t &addr, pint_t end) { uintptr_t size = (end - addr); LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr); LocalAddressSpace::pint_t sladdr = laddr; uint64_t result = LocalAddressSpace::getULEB128(laddr, laddr + size); addr += (laddr - sladdr); return result; } template int64_t OtherAddressSpace

::getSLEB128(pint_t &addr, pint_t end) { uintptr_t size = (end - addr); LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr); LocalAddressSpace::pint_t sladdr = laddr; uint64_t result = LocalAddressSpace::getSLEB128(laddr, laddr + size); addr += (laddr - sladdr); return result; } template void *OtherAddressSpace

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

::findFunctionName(pint_t addr, char *buf, size_t bufLen, unw_word_t *offset) { // FIX ME } /// unw_addr_space is the base class that abstract unw_addr_space_t type in /// libunwind.h points to. struct unw_addr_space { cpu_type_t cpuType; task_t taskPort; }; /// unw_addr_space_i386 is the concrete instance that a unw_addr_space_t points /// to when examining /// a 32-bit intel process. struct unw_addr_space_i386 : public unw_addr_space { unw_addr_space_i386(task_t task) : oas(task) {} OtherAddressSpace > oas; }; /// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t /// points to when examining /// a 64-bit intel process. struct unw_addr_space_x86_64 : public unw_addr_space { unw_addr_space_x86_64(task_t task) : oas(task) {} OtherAddressSpace > oas; }; /// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points /// to when examining /// a 32-bit PowerPC process. struct unw_addr_space_ppc : public unw_addr_space { unw_addr_space_ppc(task_t task) : oas(task) {} OtherAddressSpace > oas; }; #endif // UNW_REMOTE } // namespace libunwind #endif // __ADDRESSSPACE_HPP__ Index: head/contrib/llvm/projects/libunwind/src/CompactUnwinder.hpp =================================================================== --- head/contrib/llvm/projects/libunwind/src/CompactUnwinder.hpp (revision 302449) +++ head/contrib/llvm/projects/libunwind/src/CompactUnwinder.hpp (revision 302450) @@ -1,693 +1,699 @@ //===-------------------------- CompactUnwinder.hpp -----------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // // // Does runtime stack unwinding using compact unwind encodings. // //===----------------------------------------------------------------------===// #ifndef __COMPACT_UNWINDER_HPP__ #define __COMPACT_UNWINDER_HPP__ #include #include #include #include #include "AddressSpace.hpp" #include "Registers.hpp" #define EXTRACT_BITS(value, mask) \ ((value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask))) - 1)) namespace libunwind { +#if defined(_LIBUNWIND_TARGET_I386) /// CompactUnwinder_x86 uses a compact unwind info to virtually "step" (aka /// unwind) by modifying a Registers_x86 register set template class CompactUnwinder_x86 { public: static int stepWithCompactEncoding(compact_unwind_encoding_t info, uint32_t functionStart, A &addressSpace, Registers_x86 ®isters); private: typename A::pint_t pint_t; static void frameUnwind(A &addressSpace, Registers_x86 ®isters); static void framelessUnwind(A &addressSpace, typename A::pint_t returnAddressLocation, Registers_x86 ®isters); static int stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding, uint32_t functionStart, A &addressSpace, Registers_x86 ®isters); static int stepWithCompactEncodingFrameless( compact_unwind_encoding_t compactEncoding, uint32_t functionStart, A &addressSpace, Registers_x86 ®isters, bool indirectStackSize); }; template int CompactUnwinder_x86::stepWithCompactEncoding( compact_unwind_encoding_t compactEncoding, uint32_t functionStart, A &addressSpace, Registers_x86 ®isters) { switch (compactEncoding & UNWIND_X86_MODE_MASK) { case UNWIND_X86_MODE_EBP_FRAME: return stepWithCompactEncodingEBPFrame(compactEncoding, functionStart, addressSpace, registers); case UNWIND_X86_MODE_STACK_IMMD: return stepWithCompactEncodingFrameless(compactEncoding, functionStart, addressSpace, registers, false); case UNWIND_X86_MODE_STACK_IND: return stepWithCompactEncodingFrameless(compactEncoding, functionStart, addressSpace, registers, true); } _LIBUNWIND_ABORT("invalid compact unwind encoding"); } template int CompactUnwinder_x86::stepWithCompactEncodingEBPFrame( compact_unwind_encoding_t compactEncoding, uint32_t functionStart, A &addressSpace, Registers_x86 ®isters) { uint32_t savedRegistersOffset = EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_OFFSET); uint32_t savedRegistersLocations = EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_REGISTERS); uint32_t savedRegisters = registers.getEBP() - 4 * savedRegistersOffset; for (int i = 0; i < 5; ++i) { switch (savedRegistersLocations & 0x7) { case UNWIND_X86_REG_NONE: // no register saved in this slot break; case UNWIND_X86_REG_EBX: registers.setEBX(addressSpace.get32(savedRegisters)); break; case UNWIND_X86_REG_ECX: registers.setECX(addressSpace.get32(savedRegisters)); break; case UNWIND_X86_REG_EDX: registers.setEDX(addressSpace.get32(savedRegisters)); break; case UNWIND_X86_REG_EDI: registers.setEDI(addressSpace.get32(savedRegisters)); break; case UNWIND_X86_REG_ESI: registers.setESI(addressSpace.get32(savedRegisters)); break; default: (void)functionStart; _LIBUNWIND_DEBUG_LOG("bad register for EBP frame, encoding=%08X for " "function starting at 0x%X\n", compactEncoding, functionStart); _LIBUNWIND_ABORT("invalid compact unwind encoding"); } savedRegisters += 4; savedRegistersLocations = (savedRegistersLocations >> 3); } frameUnwind(addressSpace, registers); return UNW_STEP_SUCCESS; } template int CompactUnwinder_x86::stepWithCompactEncodingFrameless( compact_unwind_encoding_t encoding, uint32_t functionStart, A &addressSpace, Registers_x86 ®isters, bool indirectStackSize) { uint32_t stackSizeEncoded = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_SIZE); uint32_t stackAdjust = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST); uint32_t regCount = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT); uint32_t permutation = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION); uint32_t stackSize = stackSizeEncoded * 4; if (indirectStackSize) { // stack size is encoded in subl $xxx,%esp instruction uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded); stackSize = subl + 4 * stackAdjust; } // decompress permutation uint32_t permunreg[6]; switch (regCount) { case 6: permunreg[0] = permutation / 120; permutation -= (permunreg[0] * 120); permunreg[1] = permutation / 24; permutation -= (permunreg[1] * 24); permunreg[2] = permutation / 6; permutation -= (permunreg[2] * 6); permunreg[3] = permutation / 2; permutation -= (permunreg[3] * 2); permunreg[4] = permutation; permunreg[5] = 0; break; case 5: permunreg[0] = permutation / 120; permutation -= (permunreg[0] * 120); permunreg[1] = permutation / 24; permutation -= (permunreg[1] * 24); permunreg[2] = permutation / 6; permutation -= (permunreg[2] * 6); permunreg[3] = permutation / 2; permutation -= (permunreg[3] * 2); permunreg[4] = permutation; break; case 4: permunreg[0] = permutation / 60; permutation -= (permunreg[0] * 60); permunreg[1] = permutation / 12; permutation -= (permunreg[1] * 12); permunreg[2] = permutation / 3; permutation -= (permunreg[2] * 3); permunreg[3] = permutation; break; case 3: permunreg[0] = permutation / 20; permutation -= (permunreg[0] * 20); permunreg[1] = permutation / 4; permutation -= (permunreg[1] * 4); permunreg[2] = permutation; break; case 2: permunreg[0] = permutation / 5; permutation -= (permunreg[0] * 5); permunreg[1] = permutation; break; case 1: permunreg[0] = permutation; break; } // re-number registers back to standard numbers int registersSaved[6]; bool used[7] = { false, false, false, false, false, false, false }; for (uint32_t i = 0; i < regCount; ++i) { uint32_t renum = 0; for (int u = 1; u < 7; ++u) { if (!used[u]) { if (renum == permunreg[i]) { registersSaved[i] = u; used[u] = true; break; } ++renum; } } } uint32_t savedRegisters = registers.getSP() + stackSize - 4 - 4 * regCount; for (uint32_t i = 0; i < regCount; ++i) { switch (registersSaved[i]) { case UNWIND_X86_REG_EBX: registers.setEBX(addressSpace.get32(savedRegisters)); break; case UNWIND_X86_REG_ECX: registers.setECX(addressSpace.get32(savedRegisters)); break; case UNWIND_X86_REG_EDX: registers.setEDX(addressSpace.get32(savedRegisters)); break; case UNWIND_X86_REG_EDI: registers.setEDI(addressSpace.get32(savedRegisters)); break; case UNWIND_X86_REG_ESI: registers.setESI(addressSpace.get32(savedRegisters)); break; case UNWIND_X86_REG_EBP: registers.setEBP(addressSpace.get32(savedRegisters)); break; default: _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for " "function starting at 0x%X\n", encoding, functionStart); _LIBUNWIND_ABORT("invalid compact unwind encoding"); } savedRegisters += 4; } framelessUnwind(addressSpace, savedRegisters, registers); return UNW_STEP_SUCCESS; } template void CompactUnwinder_x86::frameUnwind(A &addressSpace, Registers_x86 ®isters) { typename A::pint_t bp = registers.getEBP(); // ebp points to old ebp registers.setEBP(addressSpace.get32(bp)); // old esp is ebp less saved ebp and return address registers.setSP((uint32_t)bp + 8); // pop return address into eip registers.setIP(addressSpace.get32(bp + 4)); } template void CompactUnwinder_x86::framelessUnwind( A &addressSpace, typename A::pint_t returnAddressLocation, Registers_x86 ®isters) { // return address is on stack after last saved register registers.setIP(addressSpace.get32(returnAddressLocation)); // old esp is before return address registers.setSP((uint32_t)returnAddressLocation + 4); } +#endif // _LIBUNWIND_TARGET_I386 +#if defined(_LIBUNWIND_TARGET_X86_64) /// CompactUnwinder_x86_64 uses a compact unwind info to virtually "step" (aka /// unwind) by modifying a Registers_x86_64 register set template class CompactUnwinder_x86_64 { public: static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A &addressSpace, Registers_x86_64 ®isters); private: typename A::pint_t pint_t; static void frameUnwind(A &addressSpace, Registers_x86_64 ®isters); static void framelessUnwind(A &addressSpace, uint64_t returnAddressLocation, Registers_x86_64 ®isters); static int stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A &addressSpace, Registers_x86_64 ®isters); static int stepWithCompactEncodingFrameless( compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A &addressSpace, Registers_x86_64 ®isters, bool indirectStackSize); }; template int CompactUnwinder_x86_64::stepWithCompactEncoding( compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A &addressSpace, Registers_x86_64 ®isters) { switch (compactEncoding & UNWIND_X86_64_MODE_MASK) { case UNWIND_X86_64_MODE_RBP_FRAME: return stepWithCompactEncodingRBPFrame(compactEncoding, functionStart, addressSpace, registers); case UNWIND_X86_64_MODE_STACK_IMMD: return stepWithCompactEncodingFrameless(compactEncoding, functionStart, addressSpace, registers, false); case UNWIND_X86_64_MODE_STACK_IND: return stepWithCompactEncodingFrameless(compactEncoding, functionStart, addressSpace, registers, true); } _LIBUNWIND_ABORT("invalid compact unwind encoding"); } template int CompactUnwinder_x86_64::stepWithCompactEncodingRBPFrame( compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A &addressSpace, Registers_x86_64 ®isters) { uint32_t savedRegistersOffset = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_OFFSET); uint32_t savedRegistersLocations = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_REGISTERS); uint64_t savedRegisters = registers.getRBP() - 8 * savedRegistersOffset; for (int i = 0; i < 5; ++i) { switch (savedRegistersLocations & 0x7) { case UNWIND_X86_64_REG_NONE: // no register saved in this slot break; case UNWIND_X86_64_REG_RBX: registers.setRBX(addressSpace.get64(savedRegisters)); break; case UNWIND_X86_64_REG_R12: registers.setR12(addressSpace.get64(savedRegisters)); break; case UNWIND_X86_64_REG_R13: registers.setR13(addressSpace.get64(savedRegisters)); break; case UNWIND_X86_64_REG_R14: registers.setR14(addressSpace.get64(savedRegisters)); break; case UNWIND_X86_64_REG_R15: registers.setR15(addressSpace.get64(savedRegisters)); break; default: (void)functionStart; _LIBUNWIND_DEBUG_LOG("bad register for RBP frame, encoding=%08X for " "function starting at 0x%llX\n", compactEncoding, functionStart); _LIBUNWIND_ABORT("invalid compact unwind encoding"); } savedRegisters += 8; savedRegistersLocations = (savedRegistersLocations >> 3); } frameUnwind(addressSpace, registers); return UNW_STEP_SUCCESS; } template int CompactUnwinder_x86_64::stepWithCompactEncodingFrameless( compact_unwind_encoding_t encoding, uint64_t functionStart, A &addressSpace, Registers_x86_64 ®isters, bool indirectStackSize) { uint32_t stackSizeEncoded = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE); uint32_t stackAdjust = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST); uint32_t regCount = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT); uint32_t permutation = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION); uint32_t stackSize = stackSizeEncoded * 8; if (indirectStackSize) { // stack size is encoded in subl $xxx,%esp instruction uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded); stackSize = subl + 8 * stackAdjust; } // decompress permutation uint32_t permunreg[6]; switch (regCount) { case 6: permunreg[0] = permutation / 120; permutation -= (permunreg[0] * 120); permunreg[1] = permutation / 24; permutation -= (permunreg[1] * 24); permunreg[2] = permutation / 6; permutation -= (permunreg[2] * 6); permunreg[3] = permutation / 2; permutation -= (permunreg[3] * 2); permunreg[4] = permutation; permunreg[5] = 0; break; case 5: permunreg[0] = permutation / 120; permutation -= (permunreg[0] * 120); permunreg[1] = permutation / 24; permutation -= (permunreg[1] * 24); permunreg[2] = permutation / 6; permutation -= (permunreg[2] * 6); permunreg[3] = permutation / 2; permutation -= (permunreg[3] * 2); permunreg[4] = permutation; break; case 4: permunreg[0] = permutation / 60; permutation -= (permunreg[0] * 60); permunreg[1] = permutation / 12; permutation -= (permunreg[1] * 12); permunreg[2] = permutation / 3; permutation -= (permunreg[2] * 3); permunreg[3] = permutation; break; case 3: permunreg[0] = permutation / 20; permutation -= (permunreg[0] * 20); permunreg[1] = permutation / 4; permutation -= (permunreg[1] * 4); permunreg[2] = permutation; break; case 2: permunreg[0] = permutation / 5; permutation -= (permunreg[0] * 5); permunreg[1] = permutation; break; case 1: permunreg[0] = permutation; break; } // re-number registers back to standard numbers int registersSaved[6]; bool used[7] = { false, false, false, false, false, false, false }; for (uint32_t i = 0; i < regCount; ++i) { uint32_t renum = 0; for (int u = 1; u < 7; ++u) { if (!used[u]) { if (renum == permunreg[i]) { registersSaved[i] = u; used[u] = true; break; } ++renum; } } } uint64_t savedRegisters = registers.getSP() + stackSize - 8 - 8 * regCount; for (uint32_t i = 0; i < regCount; ++i) { switch (registersSaved[i]) { case UNWIND_X86_64_REG_RBX: registers.setRBX(addressSpace.get64(savedRegisters)); break; case UNWIND_X86_64_REG_R12: registers.setR12(addressSpace.get64(savedRegisters)); break; case UNWIND_X86_64_REG_R13: registers.setR13(addressSpace.get64(savedRegisters)); break; case UNWIND_X86_64_REG_R14: registers.setR14(addressSpace.get64(savedRegisters)); break; case UNWIND_X86_64_REG_R15: registers.setR15(addressSpace.get64(savedRegisters)); break; case UNWIND_X86_64_REG_RBP: registers.setRBP(addressSpace.get64(savedRegisters)); break; default: _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for " "function starting at 0x%llX\n", encoding, functionStart); _LIBUNWIND_ABORT("invalid compact unwind encoding"); } savedRegisters += 8; } framelessUnwind(addressSpace, savedRegisters, registers); return UNW_STEP_SUCCESS; } template void CompactUnwinder_x86_64::frameUnwind(A &addressSpace, Registers_x86_64 ®isters) { uint64_t rbp = registers.getRBP(); // ebp points to old ebp registers.setRBP(addressSpace.get64(rbp)); // old esp is ebp less saved ebp and return address registers.setSP(rbp + 16); // pop return address into eip registers.setIP(addressSpace.get64(rbp + 8)); } template void CompactUnwinder_x86_64::framelessUnwind(A &addressSpace, uint64_t returnAddressLocation, Registers_x86_64 ®isters) { // return address is on stack after last saved register registers.setIP(addressSpace.get64(returnAddressLocation)); // old esp is before return address registers.setSP(returnAddressLocation + 8); } +#endif // _LIBUNWIND_TARGET_X86_64 +#if defined(_LIBUNWIND_TARGET_AARCH64) /// CompactUnwinder_arm64 uses a compact unwind info to virtually "step" (aka /// unwind) by modifying a Registers_arm64 register set template class CompactUnwinder_arm64 { public: static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A &addressSpace, Registers_arm64 ®isters); private: typename A::pint_t pint_t; static int stepWithCompactEncodingFrame(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A &addressSpace, Registers_arm64 ®isters); static int stepWithCompactEncodingFrameless( compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A &addressSpace, Registers_arm64 ®isters); }; template int CompactUnwinder_arm64::stepWithCompactEncoding( compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A &addressSpace, Registers_arm64 ®isters) { switch (compactEncoding & UNWIND_ARM64_MODE_MASK) { case UNWIND_ARM64_MODE_FRAME: return stepWithCompactEncodingFrame(compactEncoding, functionStart, addressSpace, registers); case UNWIND_ARM64_MODE_FRAMELESS: return stepWithCompactEncodingFrameless(compactEncoding, functionStart, addressSpace, registers); } _LIBUNWIND_ABORT("invalid compact unwind encoding"); } template int CompactUnwinder_arm64::stepWithCompactEncodingFrameless( compact_unwind_encoding_t encoding, uint64_t, A &addressSpace, Registers_arm64 ®isters) { uint32_t stackSize = 16 * EXTRACT_BITS(encoding, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK); uint64_t savedRegisterLoc = registers.getSP() + stackSize; if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) { registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc)); savedRegisterLoc -= 8; registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc)); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) { registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc)); savedRegisterLoc -= 8; registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc)); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) { registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc)); savedRegisterLoc -= 8; registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc)); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) { registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc)); savedRegisterLoc -= 8; registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc)); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) { registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc)); savedRegisterLoc -= 8; registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc)); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) { registers.setFloatRegister(UNW_ARM64_D8, addressSpace.getDouble(savedRegisterLoc)); savedRegisterLoc -= 8; registers.setFloatRegister(UNW_ARM64_D9, addressSpace.getDouble(savedRegisterLoc)); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) { registers.setFloatRegister(UNW_ARM64_D10, addressSpace.getDouble(savedRegisterLoc)); savedRegisterLoc -= 8; registers.setFloatRegister(UNW_ARM64_D11, addressSpace.getDouble(savedRegisterLoc)); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) { registers.setFloatRegister(UNW_ARM64_D12, addressSpace.getDouble(savedRegisterLoc)); savedRegisterLoc -= 8; registers.setFloatRegister(UNW_ARM64_D13, addressSpace.getDouble(savedRegisterLoc)); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) { registers.setFloatRegister(UNW_ARM64_D14, addressSpace.getDouble(savedRegisterLoc)); savedRegisterLoc -= 8; registers.setFloatRegister(UNW_ARM64_D15, addressSpace.getDouble(savedRegisterLoc)); savedRegisterLoc -= 8; } // subtract stack size off of sp registers.setSP(savedRegisterLoc); // set pc to be value in lr registers.setIP(registers.getRegister(UNW_ARM64_LR)); return UNW_STEP_SUCCESS; } template int CompactUnwinder_arm64::stepWithCompactEncodingFrame( compact_unwind_encoding_t encoding, uint64_t, A &addressSpace, Registers_arm64 ®isters) { uint64_t savedRegisterLoc = registers.getFP() - 8; if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) { registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc)); savedRegisterLoc -= 8; registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc)); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) { registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc)); savedRegisterLoc -= 8; registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc)); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) { registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc)); savedRegisterLoc -= 8; registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc)); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) { registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc)); savedRegisterLoc -= 8; registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc)); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) { registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc)); savedRegisterLoc -= 8; registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc)); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) { registers.setFloatRegister(UNW_ARM64_D8, addressSpace.getDouble(savedRegisterLoc)); savedRegisterLoc -= 8; registers.setFloatRegister(UNW_ARM64_D9, addressSpace.getDouble(savedRegisterLoc)); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) { registers.setFloatRegister(UNW_ARM64_D10, addressSpace.getDouble(savedRegisterLoc)); savedRegisterLoc -= 8; registers.setFloatRegister(UNW_ARM64_D11, addressSpace.getDouble(savedRegisterLoc)); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) { registers.setFloatRegister(UNW_ARM64_D12, addressSpace.getDouble(savedRegisterLoc)); savedRegisterLoc -= 8; registers.setFloatRegister(UNW_ARM64_D13, addressSpace.getDouble(savedRegisterLoc)); savedRegisterLoc -= 8; } if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) { registers.setFloatRegister(UNW_ARM64_D14, addressSpace.getDouble(savedRegisterLoc)); savedRegisterLoc -= 8; registers.setFloatRegister(UNW_ARM64_D15, addressSpace.getDouble(savedRegisterLoc)); savedRegisterLoc -= 8; } uint64_t fp = registers.getFP(); // fp points to old fp registers.setFP(addressSpace.get64(fp)); // old sp is fp less saved fp and lr registers.setSP(fp + 16); // pop return address into pc registers.setIP(addressSpace.get64(fp + 8)); return UNW_STEP_SUCCESS; } +#endif // _LIBUNWIND_TARGET_AARCH64 } // namespace libunwind #endif // __COMPACT_UNWINDER_HPP__ Index: head/contrib/llvm/projects/libunwind/src/Registers.hpp =================================================================== --- head/contrib/llvm/projects/libunwind/src/Registers.hpp (revision 302449) +++ head/contrib/llvm/projects/libunwind/src/Registers.hpp (revision 302450) @@ -1,2156 +1,2173 @@ //===----------------------------- Registers.hpp --------------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // // // Models register sets for supported processors. // //===----------------------------------------------------------------------===// #ifndef __REGISTERS_HPP__ #define __REGISTERS_HPP__ #include #include #include "libunwind.h" #include "config.h" namespace libunwind { // For emulating 128-bit registers struct v128 { uint32_t vec[4]; }; +#if defined(_LIBUNWIND_TARGET_I386) /// Registers_x86 holds the register state of a thread in a 32-bit intel /// process. class _LIBUNWIND_HIDDEN Registers_x86 { public: Registers_x86(); Registers_x86(const void *registers); bool validRegister(int num) const; uint32_t getRegister(int num) const; void setRegister(int num, uint32_t value); bool validFloatRegister(int) const { return false; } double getFloatRegister(int num) const; void setFloatRegister(int num, double value); bool validVectorRegister(int) const { return false; } v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); const char *getRegisterName(int num); void jumpto(); static int lastDwarfRegNum() { return 8; } uint32_t getSP() const { return _registers.__esp; } void setSP(uint32_t value) { _registers.__esp = value; } uint32_t getIP() const { return _registers.__eip; } void setIP(uint32_t value) { _registers.__eip = value; } uint32_t getEBP() const { return _registers.__ebp; } void setEBP(uint32_t value) { _registers.__ebp = value; } uint32_t getEBX() const { return _registers.__ebx; } void setEBX(uint32_t value) { _registers.__ebx = value; } uint32_t getECX() const { return _registers.__ecx; } void setECX(uint32_t value) { _registers.__ecx = value; } uint32_t getEDX() const { return _registers.__edx; } void setEDX(uint32_t value) { _registers.__edx = value; } uint32_t getESI() const { return _registers.__esi; } void setESI(uint32_t value) { _registers.__esi = value; } uint32_t getEDI() const { return _registers.__edi; } void setEDI(uint32_t value) { _registers.__edi = value; } private: struct GPRs { unsigned int __eax; unsigned int __ebx; unsigned int __ecx; unsigned int __edx; unsigned int __edi; unsigned int __esi; unsigned int __ebp; unsigned int __esp; unsigned int __ss; unsigned int __eflags; unsigned int __eip; unsigned int __cs; unsigned int __ds; unsigned int __es; unsigned int __fs; unsigned int __gs; }; GPRs _registers; }; inline Registers_x86::Registers_x86(const void *registers) { - static_assert(sizeof(Registers_x86) < sizeof(unw_context_t), - "x86 registers do not fit into unw_context_t"); + static_assert((check_fit::does_fit), + "x86 registers do not fit into unw_context_t"); memcpy(&_registers, registers, sizeof(_registers)); } inline Registers_x86::Registers_x86() { memset(&_registers, 0, sizeof(_registers)); } inline bool Registers_x86::validRegister(int regNum) const { if (regNum == UNW_REG_IP) return true; if (regNum == UNW_REG_SP) return true; if (regNum < 0) return false; if (regNum > 7) return false; return true; } inline uint32_t Registers_x86::getRegister(int regNum) const { switch (regNum) { case UNW_REG_IP: return _registers.__eip; case UNW_REG_SP: return _registers.__esp; case UNW_X86_EAX: return _registers.__eax; case UNW_X86_ECX: return _registers.__ecx; case UNW_X86_EDX: return _registers.__edx; case UNW_X86_EBX: return _registers.__ebx; case UNW_X86_EBP: return _registers.__ebp; case UNW_X86_ESP: return _registers.__esp; case UNW_X86_ESI: return _registers.__esi; case UNW_X86_EDI: return _registers.__edi; } _LIBUNWIND_ABORT("unsupported x86 register"); } inline void Registers_x86::setRegister(int regNum, uint32_t value) { switch (regNum) { case UNW_REG_IP: _registers.__eip = value; return; case UNW_REG_SP: _registers.__esp = value; return; case UNW_X86_EAX: _registers.__eax = value; return; case UNW_X86_ECX: _registers.__ecx = value; return; case UNW_X86_EDX: _registers.__edx = value; return; case UNW_X86_EBX: _registers.__ebx = value; return; case UNW_X86_EBP: _registers.__ebp = value; return; case UNW_X86_ESP: _registers.__esp = value; return; case UNW_X86_ESI: _registers.__esi = value; return; case UNW_X86_EDI: _registers.__edi = value; return; } _LIBUNWIND_ABORT("unsupported x86 register"); } inline const char *Registers_x86::getRegisterName(int regNum) { switch (regNum) { case UNW_REG_IP: return "ip"; case UNW_REG_SP: return "esp"; case UNW_X86_EAX: return "eax"; case UNW_X86_ECX: return "ecx"; case UNW_X86_EDX: return "edx"; case UNW_X86_EBX: return "ebx"; case UNW_X86_EBP: return "ebp"; case UNW_X86_ESP: return "esp"; case UNW_X86_ESI: return "esi"; case UNW_X86_EDI: return "edi"; default: return "unknown register"; } } inline double Registers_x86::getFloatRegister(int) const { _LIBUNWIND_ABORT("no x86 float registers"); } inline void Registers_x86::setFloatRegister(int, double) { _LIBUNWIND_ABORT("no x86 float registers"); } inline v128 Registers_x86::getVectorRegister(int) const { _LIBUNWIND_ABORT("no x86 vector registers"); } inline void Registers_x86::setVectorRegister(int, v128) { _LIBUNWIND_ABORT("no x86 vector registers"); } +#endif // _LIBUNWIND_TARGET_I386 +#if defined(_LIBUNWIND_TARGET_X86_64) /// Registers_x86_64 holds the register state of a thread in a 64-bit intel /// process. class _LIBUNWIND_HIDDEN Registers_x86_64 { public: Registers_x86_64(); Registers_x86_64(const void *registers); bool validRegister(int num) const; uint64_t getRegister(int num) const; void setRegister(int num, uint64_t value); bool validFloatRegister(int) const { return false; } double getFloatRegister(int num) const; void setFloatRegister(int num, double value); bool validVectorRegister(int) const { return false; } v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); const char *getRegisterName(int num); void jumpto(); static int lastDwarfRegNum() { return 16; } uint64_t getSP() const { return _registers.__rsp; } void setSP(uint64_t value) { _registers.__rsp = value; } uint64_t getIP() const { return _registers.__rip; } void setIP(uint64_t value) { _registers.__rip = value; } uint64_t getRBP() const { return _registers.__rbp; } void setRBP(uint64_t value) { _registers.__rbp = value; } uint64_t getRBX() const { return _registers.__rbx; } void setRBX(uint64_t value) { _registers.__rbx = value; } uint64_t getR12() const { return _registers.__r12; } void setR12(uint64_t value) { _registers.__r12 = value; } uint64_t getR13() const { return _registers.__r13; } void setR13(uint64_t value) { _registers.__r13 = value; } uint64_t getR14() const { return _registers.__r14; } void setR14(uint64_t value) { _registers.__r14 = value; } uint64_t getR15() const { return _registers.__r15; } void setR15(uint64_t value) { _registers.__r15 = value; } private: struct GPRs { uint64_t __rax; uint64_t __rbx; uint64_t __rcx; uint64_t __rdx; uint64_t __rdi; uint64_t __rsi; uint64_t __rbp; uint64_t __rsp; uint64_t __r8; uint64_t __r9; uint64_t __r10; uint64_t __r11; uint64_t __r12; uint64_t __r13; uint64_t __r14; uint64_t __r15; uint64_t __rip; uint64_t __rflags; uint64_t __cs; uint64_t __fs; uint64_t __gs; }; GPRs _registers; }; inline Registers_x86_64::Registers_x86_64(const void *registers) { - static_assert(sizeof(Registers_x86_64) < sizeof(unw_context_t), - "x86_64 registers do not fit into unw_context_t"); + static_assert((check_fit::does_fit), + "x86_64 registers do not fit into unw_context_t"); memcpy(&_registers, registers, sizeof(_registers)); } inline Registers_x86_64::Registers_x86_64() { memset(&_registers, 0, sizeof(_registers)); } inline bool Registers_x86_64::validRegister(int regNum) const { if (regNum == UNW_REG_IP) return true; if (regNum == UNW_REG_SP) return true; if (regNum < 0) return false; if (regNum > 15) return false; return true; } inline uint64_t Registers_x86_64::getRegister(int regNum) const { switch (regNum) { case UNW_REG_IP: return _registers.__rip; case UNW_REG_SP: return _registers.__rsp; case UNW_X86_64_RAX: return _registers.__rax; case UNW_X86_64_RDX: return _registers.__rdx; case UNW_X86_64_RCX: return _registers.__rcx; case UNW_X86_64_RBX: return _registers.__rbx; case UNW_X86_64_RSI: return _registers.__rsi; case UNW_X86_64_RDI: return _registers.__rdi; case UNW_X86_64_RBP: return _registers.__rbp; case UNW_X86_64_RSP: return _registers.__rsp; case UNW_X86_64_R8: return _registers.__r8; case UNW_X86_64_R9: return _registers.__r9; case UNW_X86_64_R10: return _registers.__r10; case UNW_X86_64_R11: return _registers.__r11; case UNW_X86_64_R12: return _registers.__r12; case UNW_X86_64_R13: return _registers.__r13; case UNW_X86_64_R14: return _registers.__r14; case UNW_X86_64_R15: return _registers.__r15; } _LIBUNWIND_ABORT("unsupported x86_64 register"); } inline void Registers_x86_64::setRegister(int regNum, uint64_t value) { switch (regNum) { case UNW_REG_IP: _registers.__rip = value; return; case UNW_REG_SP: _registers.__rsp = value; return; case UNW_X86_64_RAX: _registers.__rax = value; return; case UNW_X86_64_RDX: _registers.__rdx = value; return; case UNW_X86_64_RCX: _registers.__rcx = value; return; case UNW_X86_64_RBX: _registers.__rbx = value; return; case UNW_X86_64_RSI: _registers.__rsi = value; return; case UNW_X86_64_RDI: _registers.__rdi = value; return; case UNW_X86_64_RBP: _registers.__rbp = value; return; case UNW_X86_64_RSP: _registers.__rsp = value; return; case UNW_X86_64_R8: _registers.__r8 = value; return; case UNW_X86_64_R9: _registers.__r9 = value; return; case UNW_X86_64_R10: _registers.__r10 = value; return; case UNW_X86_64_R11: _registers.__r11 = value; return; case UNW_X86_64_R12: _registers.__r12 = value; return; case UNW_X86_64_R13: _registers.__r13 = value; return; case UNW_X86_64_R14: _registers.__r14 = value; return; case UNW_X86_64_R15: _registers.__r15 = value; return; } _LIBUNWIND_ABORT("unsupported x86_64 register"); } inline const char *Registers_x86_64::getRegisterName(int regNum) { switch (regNum) { case UNW_REG_IP: return "rip"; case UNW_REG_SP: return "rsp"; case UNW_X86_64_RAX: return "rax"; case UNW_X86_64_RDX: return "rdx"; case UNW_X86_64_RCX: return "rcx"; case UNW_X86_64_RBX: return "rbx"; case UNW_X86_64_RSI: return "rsi"; case UNW_X86_64_RDI: return "rdi"; case UNW_X86_64_RBP: return "rbp"; case UNW_X86_64_RSP: return "rsp"; case UNW_X86_64_R8: return "r8"; case UNW_X86_64_R9: return "r9"; case UNW_X86_64_R10: return "r10"; case UNW_X86_64_R11: return "r11"; case UNW_X86_64_R12: return "r12"; case UNW_X86_64_R13: return "r13"; case UNW_X86_64_R14: return "r14"; case UNW_X86_64_R15: return "r15"; default: return "unknown register"; } } inline double Registers_x86_64::getFloatRegister(int) const { _LIBUNWIND_ABORT("no x86_64 float registers"); } inline void Registers_x86_64::setFloatRegister(int, double) { _LIBUNWIND_ABORT("no x86_64 float registers"); } inline v128 Registers_x86_64::getVectorRegister(int) const { _LIBUNWIND_ABORT("no x86_64 vector registers"); } inline void Registers_x86_64::setVectorRegister(int, v128) { _LIBUNWIND_ABORT("no x86_64 vector registers"); } +#endif // _LIBUNWIND_TARGET_X86_64 +#if defined(_LIBUNWIND_TARGET_PPC) /// Registers_ppc holds the register state of a thread in a 32-bit PowerPC /// process. class _LIBUNWIND_HIDDEN Registers_ppc { public: Registers_ppc(); Registers_ppc(const void *registers); bool validRegister(int num) const; uint32_t getRegister(int num) const; void setRegister(int num, uint32_t value); bool validFloatRegister(int num) const; double getFloatRegister(int num) const; void setFloatRegister(int num, double value); bool validVectorRegister(int num) const; v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); const char *getRegisterName(int num); void jumpto(); static int lastDwarfRegNum() { return 112; } uint64_t getSP() const { return _registers.__r1; } void setSP(uint32_t value) { _registers.__r1 = value; } uint64_t getIP() const { return _registers.__srr0; } void setIP(uint32_t value) { _registers.__srr0 = value; } private: struct ppc_thread_state_t { unsigned int __srr0; /* Instruction address register (PC) */ unsigned int __srr1; /* Machine state register (supervisor) */ unsigned int __r0; unsigned int __r1; unsigned int __r2; unsigned int __r3; unsigned int __r4; unsigned int __r5; unsigned int __r6; unsigned int __r7; unsigned int __r8; unsigned int __r9; unsigned int __r10; unsigned int __r11; unsigned int __r12; unsigned int __r13; unsigned int __r14; unsigned int __r15; unsigned int __r16; unsigned int __r17; unsigned int __r18; unsigned int __r19; unsigned int __r20; unsigned int __r21; unsigned int __r22; unsigned int __r23; unsigned int __r24; unsigned int __r25; unsigned int __r26; unsigned int __r27; unsigned int __r28; unsigned int __r29; unsigned int __r30; unsigned int __r31; unsigned int __cr; /* Condition register */ unsigned int __xer; /* User's integer exception register */ unsigned int __lr; /* Link register */ unsigned int __ctr; /* Count register */ unsigned int __mq; /* MQ register (601 only) */ unsigned int __vrsave; /* Vector Save Register */ }; struct ppc_float_state_t { double __fpregs[32]; unsigned int __fpscr_pad; /* fpscr is 64 bits, 32 bits of rubbish */ unsigned int __fpscr; /* floating point status register */ }; ppc_thread_state_t _registers; ppc_float_state_t _floatRegisters; v128 _vectorRegisters[32]; // offset 424 }; inline Registers_ppc::Registers_ppc(const void *registers) { - static_assert(sizeof(Registers_ppc) < sizeof(unw_context_t), - "ppc registers do not fit into unw_context_t"); + static_assert((check_fit::does_fit), + "ppc registers do not fit into unw_context_t"); memcpy(&_registers, static_cast(registers), sizeof(_registers)); static_assert(sizeof(ppc_thread_state_t) == 160, "expected float register offset to be 160"); memcpy(&_floatRegisters, static_cast(registers) + sizeof(ppc_thread_state_t), sizeof(_floatRegisters)); static_assert(sizeof(ppc_thread_state_t) + sizeof(ppc_float_state_t) == 424, "expected vector register offset to be 424 bytes"); memcpy(_vectorRegisters, static_cast(registers) + sizeof(ppc_thread_state_t) + sizeof(ppc_float_state_t), sizeof(_vectorRegisters)); } inline Registers_ppc::Registers_ppc() { memset(&_registers, 0, sizeof(_registers)); memset(&_floatRegisters, 0, sizeof(_floatRegisters)); memset(&_vectorRegisters, 0, sizeof(_vectorRegisters)); } inline bool Registers_ppc::validRegister(int regNum) const { if (regNum == UNW_REG_IP) return true; if (regNum == UNW_REG_SP) return true; if (regNum == UNW_PPC_VRSAVE) return true; if (regNum < 0) return false; if (regNum <= UNW_PPC_R31) return true; if (regNum == UNW_PPC_MQ) return true; if (regNum == UNW_PPC_LR) return true; if (regNum == UNW_PPC_CTR) return true; if ((UNW_PPC_CR0 <= regNum) && (regNum <= UNW_PPC_CR7)) return true; return false; } inline uint32_t Registers_ppc::getRegister(int regNum) const { switch (regNum) { case UNW_REG_IP: return _registers.__srr0; case UNW_REG_SP: return _registers.__r1; case UNW_PPC_R0: return _registers.__r0; case UNW_PPC_R1: return _registers.__r1; case UNW_PPC_R2: return _registers.__r2; case UNW_PPC_R3: return _registers.__r3; case UNW_PPC_R4: return _registers.__r4; case UNW_PPC_R5: return _registers.__r5; case UNW_PPC_R6: return _registers.__r6; case UNW_PPC_R7: return _registers.__r7; case UNW_PPC_R8: return _registers.__r8; case UNW_PPC_R9: return _registers.__r9; case UNW_PPC_R10: return _registers.__r10; case UNW_PPC_R11: return _registers.__r11; case UNW_PPC_R12: return _registers.__r12; case UNW_PPC_R13: return _registers.__r13; case UNW_PPC_R14: return _registers.__r14; case UNW_PPC_R15: return _registers.__r15; case UNW_PPC_R16: return _registers.__r16; case UNW_PPC_R17: return _registers.__r17; case UNW_PPC_R18: return _registers.__r18; case UNW_PPC_R19: return _registers.__r19; case UNW_PPC_R20: return _registers.__r20; case UNW_PPC_R21: return _registers.__r21; case UNW_PPC_R22: return _registers.__r22; case UNW_PPC_R23: return _registers.__r23; case UNW_PPC_R24: return _registers.__r24; case UNW_PPC_R25: return _registers.__r25; case UNW_PPC_R26: return _registers.__r26; case UNW_PPC_R27: return _registers.__r27; case UNW_PPC_R28: return _registers.__r28; case UNW_PPC_R29: return _registers.__r29; case UNW_PPC_R30: return _registers.__r30; case UNW_PPC_R31: return _registers.__r31; case UNW_PPC_LR: return _registers.__lr; case UNW_PPC_CR0: return (_registers.__cr & 0xF0000000); case UNW_PPC_CR1: return (_registers.__cr & 0x0F000000); case UNW_PPC_CR2: return (_registers.__cr & 0x00F00000); case UNW_PPC_CR3: return (_registers.__cr & 0x000F0000); case UNW_PPC_CR4: return (_registers.__cr & 0x0000F000); case UNW_PPC_CR5: return (_registers.__cr & 0x00000F00); case UNW_PPC_CR6: return (_registers.__cr & 0x000000F0); case UNW_PPC_CR7: return (_registers.__cr & 0x0000000F); case UNW_PPC_VRSAVE: return _registers.__vrsave; } _LIBUNWIND_ABORT("unsupported ppc register"); } inline void Registers_ppc::setRegister(int regNum, uint32_t value) { //fprintf(stderr, "Registers_ppc::setRegister(%d, 0x%08X)\n", regNum, value); switch (regNum) { case UNW_REG_IP: _registers.__srr0 = value; return; case UNW_REG_SP: _registers.__r1 = value; return; case UNW_PPC_R0: _registers.__r0 = value; return; case UNW_PPC_R1: _registers.__r1 = value; return; case UNW_PPC_R2: _registers.__r2 = value; return; case UNW_PPC_R3: _registers.__r3 = value; return; case UNW_PPC_R4: _registers.__r4 = value; return; case UNW_PPC_R5: _registers.__r5 = value; return; case UNW_PPC_R6: _registers.__r6 = value; return; case UNW_PPC_R7: _registers.__r7 = value; return; case UNW_PPC_R8: _registers.__r8 = value; return; case UNW_PPC_R9: _registers.__r9 = value; return; case UNW_PPC_R10: _registers.__r10 = value; return; case UNW_PPC_R11: _registers.__r11 = value; return; case UNW_PPC_R12: _registers.__r12 = value; return; case UNW_PPC_R13: _registers.__r13 = value; return; case UNW_PPC_R14: _registers.__r14 = value; return; case UNW_PPC_R15: _registers.__r15 = value; return; case UNW_PPC_R16: _registers.__r16 = value; return; case UNW_PPC_R17: _registers.__r17 = value; return; case UNW_PPC_R18: _registers.__r18 = value; return; case UNW_PPC_R19: _registers.__r19 = value; return; case UNW_PPC_R20: _registers.__r20 = value; return; case UNW_PPC_R21: _registers.__r21 = value; return; case UNW_PPC_R22: _registers.__r22 = value; return; case UNW_PPC_R23: _registers.__r23 = value; return; case UNW_PPC_R24: _registers.__r24 = value; return; case UNW_PPC_R25: _registers.__r25 = value; return; case UNW_PPC_R26: _registers.__r26 = value; return; case UNW_PPC_R27: _registers.__r27 = value; return; case UNW_PPC_R28: _registers.__r28 = value; return; case UNW_PPC_R29: _registers.__r29 = value; return; case UNW_PPC_R30: _registers.__r30 = value; return; case UNW_PPC_R31: _registers.__r31 = value; return; case UNW_PPC_MQ: _registers.__mq = value; return; case UNW_PPC_LR: _registers.__lr = value; return; case UNW_PPC_CTR: _registers.__ctr = value; return; case UNW_PPC_CR0: _registers.__cr &= 0x0FFFFFFF; _registers.__cr |= (value & 0xF0000000); return; case UNW_PPC_CR1: _registers.__cr &= 0xF0FFFFFF; _registers.__cr |= (value & 0x0F000000); return; case UNW_PPC_CR2: _registers.__cr &= 0xFF0FFFFF; _registers.__cr |= (value & 0x00F00000); return; case UNW_PPC_CR3: _registers.__cr &= 0xFFF0FFFF; _registers.__cr |= (value & 0x000F0000); return; case UNW_PPC_CR4: _registers.__cr &= 0xFFFF0FFF; _registers.__cr |= (value & 0x0000F000); return; case UNW_PPC_CR5: _registers.__cr &= 0xFFFFF0FF; _registers.__cr |= (value & 0x00000F00); return; case UNW_PPC_CR6: _registers.__cr &= 0xFFFFFF0F; _registers.__cr |= (value & 0x000000F0); return; case UNW_PPC_CR7: _registers.__cr &= 0xFFFFFFF0; _registers.__cr |= (value & 0x0000000F); return; case UNW_PPC_VRSAVE: _registers.__vrsave = value; return; // not saved return; case UNW_PPC_XER: _registers.__xer = value; return; case UNW_PPC_AP: case UNW_PPC_VSCR: case UNW_PPC_SPEFSCR: // not saved return; } _LIBUNWIND_ABORT("unsupported ppc register"); } inline bool Registers_ppc::validFloatRegister(int regNum) const { if (regNum < UNW_PPC_F0) return false; if (regNum > UNW_PPC_F31) return false; return true; } inline double Registers_ppc::getFloatRegister(int regNum) const { assert(validFloatRegister(regNum)); return _floatRegisters.__fpregs[regNum - UNW_PPC_F0]; } inline void Registers_ppc::setFloatRegister(int regNum, double value) { assert(validFloatRegister(regNum)); _floatRegisters.__fpregs[regNum - UNW_PPC_F0] = value; } inline bool Registers_ppc::validVectorRegister(int regNum) const { if (regNum < UNW_PPC_V0) return false; if (regNum > UNW_PPC_V31) return false; return true; } inline v128 Registers_ppc::getVectorRegister(int regNum) const { assert(validVectorRegister(regNum)); v128 result = _vectorRegisters[regNum - UNW_PPC_V0]; return result; } inline void Registers_ppc::setVectorRegister(int regNum, v128 value) { assert(validVectorRegister(regNum)); _vectorRegisters[regNum - UNW_PPC_V0] = value; } inline const char *Registers_ppc::getRegisterName(int regNum) { switch (regNum) { case UNW_REG_IP: return "ip"; case UNW_REG_SP: return "sp"; case UNW_PPC_R0: return "r0"; case UNW_PPC_R1: return "r1"; case UNW_PPC_R2: return "r2"; case UNW_PPC_R3: return "r3"; case UNW_PPC_R4: return "r4"; case UNW_PPC_R5: return "r5"; case UNW_PPC_R6: return "r6"; case UNW_PPC_R7: return "r7"; case UNW_PPC_R8: return "r8"; case UNW_PPC_R9: return "r9"; case UNW_PPC_R10: return "r10"; case UNW_PPC_R11: return "r11"; case UNW_PPC_R12: return "r12"; case UNW_PPC_R13: return "r13"; case UNW_PPC_R14: return "r14"; case UNW_PPC_R15: return "r15"; case UNW_PPC_R16: return "r16"; case UNW_PPC_R17: return "r17"; case UNW_PPC_R18: return "r18"; case UNW_PPC_R19: return "r19"; case UNW_PPC_R20: return "r20"; case UNW_PPC_R21: return "r21"; case UNW_PPC_R22: return "r22"; case UNW_PPC_R23: return "r23"; case UNW_PPC_R24: return "r24"; case UNW_PPC_R25: return "r25"; case UNW_PPC_R26: return "r26"; case UNW_PPC_R27: return "r27"; case UNW_PPC_R28: return "r28"; case UNW_PPC_R29: return "r29"; case UNW_PPC_R30: return "r30"; case UNW_PPC_R31: return "r31"; case UNW_PPC_F0: return "fp0"; case UNW_PPC_F1: return "fp1"; case UNW_PPC_F2: return "fp2"; case UNW_PPC_F3: return "fp3"; case UNW_PPC_F4: return "fp4"; case UNW_PPC_F5: return "fp5"; case UNW_PPC_F6: return "fp6"; case UNW_PPC_F7: return "fp7"; case UNW_PPC_F8: return "fp8"; case UNW_PPC_F9: return "fp9"; case UNW_PPC_F10: return "fp10"; case UNW_PPC_F11: return "fp11"; case UNW_PPC_F12: return "fp12"; case UNW_PPC_F13: return "fp13"; case UNW_PPC_F14: return "fp14"; case UNW_PPC_F15: return "fp15"; case UNW_PPC_F16: return "fp16"; case UNW_PPC_F17: return "fp17"; case UNW_PPC_F18: return "fp18"; case UNW_PPC_F19: return "fp19"; case UNW_PPC_F20: return "fp20"; case UNW_PPC_F21: return "fp21"; case UNW_PPC_F22: return "fp22"; case UNW_PPC_F23: return "fp23"; case UNW_PPC_F24: return "fp24"; case UNW_PPC_F25: return "fp25"; case UNW_PPC_F26: return "fp26"; case UNW_PPC_F27: return "fp27"; case UNW_PPC_F28: return "fp28"; case UNW_PPC_F29: return "fp29"; case UNW_PPC_F30: return "fp30"; case UNW_PPC_F31: return "fp31"; case UNW_PPC_LR: return "lr"; default: return "unknown register"; } } +#endif // _LIBUNWIND_TARGET_PPC -/// Registers_riscv holds the register state of a thread in a 64-bit RISC-V -/// process. -class _LIBUNWIND_HIDDEN Registers_riscv { -public: - Registers_riscv(); - Registers_riscv(const void *registers); - bool validRegister(int num) const; - uint64_t getRegister(int num) const; - void setRegister(int num, uint64_t value); - bool validFloatRegister(int num) const; - double getFloatRegister(int num) const; - void setFloatRegister(int num, double value); - bool validVectorRegister(int num) const; - v128 getVectorRegister(int num) const; - void setVectorRegister(int num, v128 value); - const char *getRegisterName(int num); - void jumpto(); - static int lastDwarfRegNum() { return 95; } - - uint64_t getSP() const { return _registers.__x[2]; } - void setSP(uint64_t value) { _registers.__x[2] = value; } - uint64_t getIP() const { return _registers.__x[1]; } - void setIP(uint64_t value) { _registers.__x[1] = value; } - -private: - struct GPRs { - uint64_t __x[32]; // x0-x31 - }; - - GPRs _registers; - double _vectorHalfRegisters[32]; - // Currently only the lower double in 128-bit vectore registers - // is perserved during unwinding. We could define new register - // numbers (> 96) which mean whole vector registers, then this - // struct would need to change to contain whole vector registers. -}; - -inline Registers_riscv::Registers_riscv(const void *registers) { - static_assert(sizeof(Registers_riscv) < sizeof(unw_context_t), - "riscv registers do not fit into unw_context_t"); - memcpy(&_registers, registers, sizeof(_registers)); - static_assert(sizeof(GPRs) == 0x100, - "expected VFP registers to be at offset 256"); - memcpy(_vectorHalfRegisters, - static_cast(registers) + sizeof(GPRs), - sizeof(_vectorHalfRegisters)); -} - -inline Registers_riscv::Registers_riscv() { - memset(&_registers, 0, sizeof(_registers)); - memset(&_vectorHalfRegisters, 0, sizeof(_vectorHalfRegisters)); -} - -inline bool Registers_riscv::validRegister(int regNum) const { - if (regNum == UNW_REG_IP) - return true; - if (regNum == UNW_REG_SP) - return true; - if (regNum < 0) - return false; - if (regNum > 95) - return false; - if ((regNum > 31) && (regNum < 64)) - return false; - return true; -} - -inline uint64_t Registers_riscv::getRegister(int regNum) const { - if (regNum == UNW_REG_IP) - return _registers.__x[1]; - if (regNum == UNW_REG_SP) - return _registers.__x[2]; - if ((regNum >= 0) && (regNum < 32)) - return _registers.__x[regNum]; - _LIBUNWIND_ABORT("unsupported riscv register"); -} - -inline void Registers_riscv::setRegister(int regNum, uint64_t value) { - if (regNum == UNW_REG_IP) - _registers.__x[1] = value; - else if (regNum == UNW_REG_SP) - _registers.__x[2] = value; - else if ((regNum >= 0) && (regNum < 32)) - _registers.__x[regNum] = value; - else - _LIBUNWIND_ABORT("unsupported riscv register"); -} - -inline const char *Registers_riscv::getRegisterName(int regNum) { - switch (regNum) { - case UNW_REG_IP: - return "ra"; - case UNW_REG_SP: - return "sp"; - case UNW_RISCV_X0: - return "x0"; - case UNW_RISCV_X1: - return "ra"; - case UNW_RISCV_X2: - return "sp"; - case UNW_RISCV_X3: - return "x3"; - case UNW_RISCV_X4: - return "x4"; - case UNW_RISCV_X5: - return "x5"; - case UNW_RISCV_X6: - return "x6"; - case UNW_RISCV_X7: - return "x7"; - case UNW_RISCV_X8: - return "x8"; - case UNW_RISCV_X9: - return "x9"; - case UNW_RISCV_X10: - return "x10"; - case UNW_RISCV_X11: - return "x11"; - case UNW_RISCV_X12: - return "x12"; - case UNW_RISCV_X13: - return "x13"; - case UNW_RISCV_X14: - return "x14"; - case UNW_RISCV_X15: - return "x15"; - case UNW_RISCV_X16: - return "x16"; - case UNW_RISCV_X17: - return "x17"; - case UNW_RISCV_X18: - return "x18"; - case UNW_RISCV_X19: - return "x19"; - case UNW_RISCV_X20: - return "x20"; - case UNW_RISCV_X21: - return "x21"; - case UNW_RISCV_X22: - return "x22"; - case UNW_RISCV_X23: - return "x23"; - case UNW_RISCV_X24: - return "x24"; - case UNW_RISCV_X25: - return "x25"; - case UNW_RISCV_X26: - return "x26"; - case UNW_RISCV_X27: - return "x27"; - case UNW_RISCV_X28: - return "x28"; - case UNW_RISCV_X29: - return "x29"; - case UNW_RISCV_X30: - return "x30"; - case UNW_RISCV_X31: - return "x31"; - case UNW_RISCV_D0: - return "d0"; - case UNW_RISCV_D1: - return "d1"; - case UNW_RISCV_D2: - return "d2"; - case UNW_RISCV_D3: - return "d3"; - case UNW_RISCV_D4: - return "d4"; - case UNW_RISCV_D5: - return "d5"; - case UNW_RISCV_D6: - return "d6"; - case UNW_RISCV_D7: - return "d7"; - case UNW_RISCV_D8: - return "d8"; - case UNW_RISCV_D9: - return "d9"; - case UNW_RISCV_D10: - return "d10"; - case UNW_RISCV_D11: - return "d11"; - case UNW_RISCV_D12: - return "d12"; - case UNW_RISCV_D13: - return "d13"; - case UNW_RISCV_D14: - return "d14"; - case UNW_RISCV_D15: - return "d15"; - case UNW_RISCV_D16: - return "d16"; - case UNW_RISCV_D17: - return "d17"; - case UNW_RISCV_D18: - return "d18"; - case UNW_RISCV_D19: - return "d19"; - case UNW_RISCV_D20: - return "d20"; - case UNW_RISCV_D21: - return "d21"; - case UNW_RISCV_D22: - return "d22"; - case UNW_RISCV_D23: - return "d23"; - case UNW_RISCV_D24: - return "d24"; - case UNW_RISCV_D25: - return "d25"; - case UNW_RISCV_D26: - return "d26"; - case UNW_RISCV_D27: - return "d27"; - case UNW_RISCV_D28: - return "d28"; - case UNW_RISCV_D29: - return "d29"; - case UNW_RISCV_D30: - return "d30"; - case UNW_RISCV_D31: - return "d31"; - default: - return "unknown register"; - } -} - -inline bool Registers_riscv::validFloatRegister(int regNum) const { - if (regNum < UNW_RISCV_D0) - return false; - if (regNum > UNW_RISCV_D31) - return false; - return true; -} - -inline double Registers_riscv::getFloatRegister(int regNum) const { - assert(validFloatRegister(regNum)); - return _vectorHalfRegisters[regNum - UNW_RISCV_D0]; -} - -inline void Registers_riscv::setFloatRegister(int regNum, double value) { - assert(validFloatRegister(regNum)); - _vectorHalfRegisters[regNum - UNW_RISCV_D0] = value; -} - -inline bool Registers_riscv::validVectorRegister(int) const { - return false; -} - -inline v128 Registers_riscv::getVectorRegister(int) const { - _LIBUNWIND_ABORT("no riscv vector register support yet"); -} - -inline void Registers_riscv::setVectorRegister(int, v128) { - _LIBUNWIND_ABORT("no riscv vector register support yet"); -} - - +#if defined(_LIBUNWIND_TARGET_AARCH64) /// Registers_arm64 holds the register state of a thread in a 64-bit arm /// process. class _LIBUNWIND_HIDDEN Registers_arm64 { public: Registers_arm64(); Registers_arm64(const void *registers); bool validRegister(int num) const; uint64_t getRegister(int num) const; void setRegister(int num, uint64_t value); bool validFloatRegister(int num) const; double getFloatRegister(int num) const; void setFloatRegister(int num, double value); bool validVectorRegister(int num) const; v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); const char *getRegisterName(int num); void jumpto(); static int lastDwarfRegNum() { return 95; } uint64_t getSP() const { return _registers.__sp; } void setSP(uint64_t value) { _registers.__sp = value; } uint64_t getIP() const { return _registers.__pc; } void setIP(uint64_t value) { _registers.__pc = value; } uint64_t getFP() const { return _registers.__fp; } void setFP(uint64_t value) { _registers.__fp = value; } private: struct GPRs { uint64_t __x[29]; // x0-x28 uint64_t __fp; // Frame pointer x29 uint64_t __lr; // Link register x30 uint64_t __sp; // Stack pointer x31 uint64_t __pc; // Program counter uint64_t padding; // 16-byte align }; GPRs _registers; double _vectorHalfRegisters[32]; // Currently only the lower double in 128-bit vectore registers // is perserved during unwinding. We could define new register // numbers (> 96) which mean whole vector registers, then this // struct would need to change to contain whole vector registers. }; inline Registers_arm64::Registers_arm64(const void *registers) { - static_assert(sizeof(Registers_arm64) < sizeof(unw_context_t), - "arm64 registers do not fit into unw_context_t"); + static_assert((check_fit::does_fit), + "arm64 registers do not fit into unw_context_t"); memcpy(&_registers, registers, sizeof(_registers)); static_assert(sizeof(GPRs) == 0x110, "expected VFP registers to be at offset 272"); memcpy(_vectorHalfRegisters, static_cast(registers) + sizeof(GPRs), sizeof(_vectorHalfRegisters)); } inline Registers_arm64::Registers_arm64() { memset(&_registers, 0, sizeof(_registers)); memset(&_vectorHalfRegisters, 0, sizeof(_vectorHalfRegisters)); } inline bool Registers_arm64::validRegister(int regNum) const { if (regNum == UNW_REG_IP) return true; if (regNum == UNW_REG_SP) return true; if (regNum < 0) return false; if (regNum > 95) return false; if ((regNum > 31) && (regNum < 64)) return false; return true; } inline uint64_t Registers_arm64::getRegister(int regNum) const { if (regNum == UNW_REG_IP) return _registers.__pc; if (regNum == UNW_REG_SP) return _registers.__sp; if ((regNum >= 0) && (regNum < 32)) return _registers.__x[regNum]; _LIBUNWIND_ABORT("unsupported arm64 register"); } inline void Registers_arm64::setRegister(int regNum, uint64_t value) { if (regNum == UNW_REG_IP) _registers.__pc = value; else if (regNum == UNW_REG_SP) _registers.__sp = value; else if ((regNum >= 0) && (regNum < 32)) _registers.__x[regNum] = value; else _LIBUNWIND_ABORT("unsupported arm64 register"); } inline const char *Registers_arm64::getRegisterName(int regNum) { switch (regNum) { case UNW_REG_IP: return "pc"; case UNW_REG_SP: return "sp"; case UNW_ARM64_X0: return "x0"; case UNW_ARM64_X1: return "x1"; case UNW_ARM64_X2: return "x2"; case UNW_ARM64_X3: return "x3"; case UNW_ARM64_X4: return "x4"; case UNW_ARM64_X5: return "x5"; case UNW_ARM64_X6: return "x6"; case UNW_ARM64_X7: return "x7"; case UNW_ARM64_X8: return "x8"; case UNW_ARM64_X9: return "x9"; case UNW_ARM64_X10: return "x10"; case UNW_ARM64_X11: return "x11"; case UNW_ARM64_X12: return "x12"; case UNW_ARM64_X13: return "x13"; case UNW_ARM64_X14: return "x14"; case UNW_ARM64_X15: return "x15"; case UNW_ARM64_X16: return "x16"; case UNW_ARM64_X17: return "x17"; case UNW_ARM64_X18: return "x18"; case UNW_ARM64_X19: return "x19"; case UNW_ARM64_X20: return "x20"; case UNW_ARM64_X21: return "x21"; case UNW_ARM64_X22: return "x22"; case UNW_ARM64_X23: return "x23"; case UNW_ARM64_X24: return "x24"; case UNW_ARM64_X25: return "x25"; case UNW_ARM64_X26: return "x26"; case UNW_ARM64_X27: return "x27"; case UNW_ARM64_X28: return "x28"; case UNW_ARM64_X29: return "fp"; case UNW_ARM64_X30: return "lr"; case UNW_ARM64_X31: return "sp"; case UNW_ARM64_D0: return "d0"; case UNW_ARM64_D1: return "d1"; case UNW_ARM64_D2: return "d2"; case UNW_ARM64_D3: return "d3"; case UNW_ARM64_D4: return "d4"; case UNW_ARM64_D5: return "d5"; case UNW_ARM64_D6: return "d6"; case UNW_ARM64_D7: return "d7"; case UNW_ARM64_D8: return "d8"; case UNW_ARM64_D9: return "d9"; case UNW_ARM64_D10: return "d10"; case UNW_ARM64_D11: return "d11"; case UNW_ARM64_D12: return "d12"; case UNW_ARM64_D13: return "d13"; case UNW_ARM64_D14: return "d14"; case UNW_ARM64_D15: return "d15"; case UNW_ARM64_D16: return "d16"; case UNW_ARM64_D17: return "d17"; case UNW_ARM64_D18: return "d18"; case UNW_ARM64_D19: return "d19"; case UNW_ARM64_D20: return "d20"; case UNW_ARM64_D21: return "d21"; case UNW_ARM64_D22: return "d22"; case UNW_ARM64_D23: return "d23"; case UNW_ARM64_D24: return "d24"; case UNW_ARM64_D25: return "d25"; case UNW_ARM64_D26: return "d26"; case UNW_ARM64_D27: return "d27"; case UNW_ARM64_D28: return "d28"; case UNW_ARM64_D29: return "d29"; case UNW_ARM64_D30: return "d30"; case UNW_ARM64_D31: return "d31"; default: return "unknown register"; } } inline bool Registers_arm64::validFloatRegister(int regNum) const { if (regNum < UNW_ARM64_D0) return false; if (regNum > UNW_ARM64_D31) return false; return true; } inline double Registers_arm64::getFloatRegister(int regNum) const { assert(validFloatRegister(regNum)); return _vectorHalfRegisters[regNum - UNW_ARM64_D0]; } inline void Registers_arm64::setFloatRegister(int regNum, double value) { assert(validFloatRegister(regNum)); _vectorHalfRegisters[regNum - UNW_ARM64_D0] = value; } inline bool Registers_arm64::validVectorRegister(int) const { return false; } inline v128 Registers_arm64::getVectorRegister(int) const { _LIBUNWIND_ABORT("no arm64 vector register support yet"); } inline void Registers_arm64::setVectorRegister(int, v128) { _LIBUNWIND_ABORT("no arm64 vector register support yet"); } +#endif // _LIBUNWIND_TARGET_AARCH64 +#if defined(_LIBUNWIND_TARGET_ARM) /// Registers_arm holds the register state of a thread in a 32-bit arm /// process. /// /// NOTE: Assumes VFPv3. On ARM processors without a floating point unit, /// this uses more memory than required. class _LIBUNWIND_HIDDEN Registers_arm { public: Registers_arm(); Registers_arm(const void *registers); bool validRegister(int num) const; uint32_t getRegister(int num); void setRegister(int num, uint32_t value); bool validFloatRegister(int num) const; unw_fpreg_t getFloatRegister(int num); void setFloatRegister(int num, unw_fpreg_t value); bool validVectorRegister(int num) const; v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); const char *getRegisterName(int num); void jumpto() { restoreSavedFloatRegisters(); restoreCoreAndJumpTo(); } uint32_t getSP() const { return _registers.__sp; } void setSP(uint32_t value) { _registers.__sp = value; } uint32_t getIP() const { return _registers.__pc; } void setIP(uint32_t value) { _registers.__pc = value; } void saveVFPAsX() { assert(_use_X_for_vfp_save || !_saved_vfp_d0_d15); _use_X_for_vfp_save = true; } void restoreSavedFloatRegisters() { if (_saved_vfp_d0_d15) { if (_use_X_for_vfp_save) restoreVFPWithFLDMX(_vfp_d0_d15_pad); else restoreVFPWithFLDMD(_vfp_d0_d15_pad); } if (_saved_vfp_d16_d31) restoreVFPv3(_vfp_d16_d31); if (_saved_iwmmx) restoreiWMMX(_iwmmx); if (_saved_iwmmx_control) restoreiWMMXControl(_iwmmx_control); } private: struct GPRs { uint32_t __r[13]; // r0-r12 uint32_t __sp; // Stack pointer r13 uint32_t __lr; // Link register r14 uint32_t __pc; // Program counter r15 }; static void saveVFPWithFSTMD(unw_fpreg_t*); static void saveVFPWithFSTMX(unw_fpreg_t*); static void saveVFPv3(unw_fpreg_t*); static void saveiWMMX(unw_fpreg_t*); static void saveiWMMXControl(uint32_t*); static void restoreVFPWithFLDMD(unw_fpreg_t*); static void restoreVFPWithFLDMX(unw_fpreg_t*); static void restoreVFPv3(unw_fpreg_t*); static void restoreiWMMX(unw_fpreg_t*); static void restoreiWMMXControl(uint32_t*); void restoreCoreAndJumpTo(); // ARM registers GPRs _registers; // We save floating point registers lazily because we can't know ahead of // time which ones are used. See EHABI #4.7. // Whether D0-D15 are saved in the FTSMX instead of FSTMD format. // // See EHABI #7.5 that explains how matching instruction sequences for load // and store need to be used to correctly restore the exact register bits. bool _use_X_for_vfp_save; // Whether VFP D0-D15 are saved. bool _saved_vfp_d0_d15; // Whether VFPv3 D16-D31 are saved. bool _saved_vfp_d16_d31; // Whether iWMMX data registers are saved. bool _saved_iwmmx; // Whether iWMMX control registers are saved. bool _saved_iwmmx_control; // VFP registers D0-D15, + padding if saved using FSTMX unw_fpreg_t _vfp_d0_d15_pad[17]; // VFPv3 registers D16-D31, always saved using FSTMD unw_fpreg_t _vfp_d16_d31[16]; // iWMMX registers unw_fpreg_t _iwmmx[16]; // iWMMX control registers uint32_t _iwmmx_control[4]; }; inline Registers_arm::Registers_arm(const void *registers) : _use_X_for_vfp_save(false), _saved_vfp_d0_d15(false), _saved_vfp_d16_d31(false), _saved_iwmmx(false), _saved_iwmmx_control(false) { - static_assert(sizeof(Registers_arm) < sizeof(unw_context_t), - "arm registers do not fit into unw_context_t"); + static_assert((check_fit::does_fit), + "arm registers do not fit into unw_context_t"); // See unw_getcontext() note about data. memcpy(&_registers, registers, sizeof(_registers)); memset(&_vfp_d0_d15_pad, 0, sizeof(_vfp_d0_d15_pad)); memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31)); memset(&_iwmmx, 0, sizeof(_iwmmx)); memset(&_iwmmx_control, 0, sizeof(_iwmmx_control)); } inline Registers_arm::Registers_arm() : _use_X_for_vfp_save(false), _saved_vfp_d0_d15(false), _saved_vfp_d16_d31(false), _saved_iwmmx(false), _saved_iwmmx_control(false) { memset(&_registers, 0, sizeof(_registers)); memset(&_vfp_d0_d15_pad, 0, sizeof(_vfp_d0_d15_pad)); memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31)); memset(&_iwmmx, 0, sizeof(_iwmmx)); memset(&_iwmmx_control, 0, sizeof(_iwmmx_control)); } inline bool Registers_arm::validRegister(int regNum) const { // Returns true for all non-VFP registers supported by the EHABI // virtual register set (VRS). if (regNum == UNW_REG_IP) return true; if (regNum == UNW_REG_SP) return true; if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R15) return true; if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) return true; return false; } inline uint32_t Registers_arm::getRegister(int regNum) { if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP) return _registers.__sp; if (regNum == UNW_ARM_LR) return _registers.__lr; if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP) return _registers.__pc; if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R12) return _registers.__r[regNum]; if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) { if (!_saved_iwmmx_control) { _saved_iwmmx_control = true; saveiWMMXControl(_iwmmx_control); } return _iwmmx_control[regNum - UNW_ARM_WC0]; } _LIBUNWIND_ABORT("unsupported arm register"); } inline void Registers_arm::setRegister(int regNum, uint32_t value) { if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP) _registers.__sp = value; else if (regNum == UNW_ARM_LR) _registers.__lr = value; else if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP) _registers.__pc = value; else if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R12) _registers.__r[regNum] = value; else if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) { if (!_saved_iwmmx_control) { _saved_iwmmx_control = true; saveiWMMXControl(_iwmmx_control); } _iwmmx_control[regNum - UNW_ARM_WC0] = value; } else _LIBUNWIND_ABORT("unsupported arm register"); } inline const char *Registers_arm::getRegisterName(int regNum) { switch (regNum) { case UNW_REG_IP: case UNW_ARM_IP: // UNW_ARM_R15 is alias return "pc"; case UNW_ARM_LR: // UNW_ARM_R14 is alias return "lr"; case UNW_REG_SP: case UNW_ARM_SP: // UNW_ARM_R13 is alias return "sp"; case UNW_ARM_R0: return "r0"; case UNW_ARM_R1: return "r1"; case UNW_ARM_R2: return "r2"; case UNW_ARM_R3: return "r3"; case UNW_ARM_R4: return "r4"; case UNW_ARM_R5: return "r5"; case UNW_ARM_R6: return "r6"; case UNW_ARM_R7: return "r7"; case UNW_ARM_R8: return "r8"; case UNW_ARM_R9: return "r9"; case UNW_ARM_R10: return "r10"; case UNW_ARM_R11: return "r11"; case UNW_ARM_R12: return "r12"; case UNW_ARM_S0: return "s0"; case UNW_ARM_S1: return "s1"; case UNW_ARM_S2: return "s2"; case UNW_ARM_S3: return "s3"; case UNW_ARM_S4: return "s4"; case UNW_ARM_S5: return "s5"; case UNW_ARM_S6: return "s6"; case UNW_ARM_S7: return "s7"; case UNW_ARM_S8: return "s8"; case UNW_ARM_S9: return "s9"; case UNW_ARM_S10: return "s10"; case UNW_ARM_S11: return "s11"; case UNW_ARM_S12: return "s12"; case UNW_ARM_S13: return "s13"; case UNW_ARM_S14: return "s14"; case UNW_ARM_S15: return "s15"; case UNW_ARM_S16: return "s16"; case UNW_ARM_S17: return "s17"; case UNW_ARM_S18: return "s18"; case UNW_ARM_S19: return "s19"; case UNW_ARM_S20: return "s20"; case UNW_ARM_S21: return "s21"; case UNW_ARM_S22: return "s22"; case UNW_ARM_S23: return "s23"; case UNW_ARM_S24: return "s24"; case UNW_ARM_S25: return "s25"; case UNW_ARM_S26: return "s26"; case UNW_ARM_S27: return "s27"; case UNW_ARM_S28: return "s28"; case UNW_ARM_S29: return "s29"; case UNW_ARM_S30: return "s30"; case UNW_ARM_S31: return "s31"; case UNW_ARM_D0: return "d0"; case UNW_ARM_D1: return "d1"; case UNW_ARM_D2: return "d2"; case UNW_ARM_D3: return "d3"; case UNW_ARM_D4: return "d4"; case UNW_ARM_D5: return "d5"; case UNW_ARM_D6: return "d6"; case UNW_ARM_D7: return "d7"; case UNW_ARM_D8: return "d8"; case UNW_ARM_D9: return "d9"; case UNW_ARM_D10: return "d10"; case UNW_ARM_D11: return "d11"; case UNW_ARM_D12: return "d12"; case UNW_ARM_D13: return "d13"; case UNW_ARM_D14: return "d14"; case UNW_ARM_D15: return "d15"; case UNW_ARM_D16: return "d16"; case UNW_ARM_D17: return "d17"; case UNW_ARM_D18: return "d18"; case UNW_ARM_D19: return "d19"; case UNW_ARM_D20: return "d20"; case UNW_ARM_D21: return "d21"; case UNW_ARM_D22: return "d22"; case UNW_ARM_D23: return "d23"; case UNW_ARM_D24: return "d24"; case UNW_ARM_D25: return "d25"; case UNW_ARM_D26: return "d26"; case UNW_ARM_D27: return "d27"; case UNW_ARM_D28: return "d28"; case UNW_ARM_D29: return "d29"; case UNW_ARM_D30: return "d30"; case UNW_ARM_D31: return "d31"; default: return "unknown register"; } } inline bool Registers_arm::validFloatRegister(int regNum) const { // NOTE: Consider the intel MMX registers floating points so the // unw_get_fpreg can be used to transmit the 64-bit data back. return ((regNum >= UNW_ARM_D0) && (regNum <= UNW_ARM_D31)) || ((regNum >= UNW_ARM_WR0) && (regNum <= UNW_ARM_WR15)); } inline unw_fpreg_t Registers_arm::getFloatRegister(int regNum) { if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D15) { if (!_saved_vfp_d0_d15) { _saved_vfp_d0_d15 = true; if (_use_X_for_vfp_save) saveVFPWithFSTMX(_vfp_d0_d15_pad); else saveVFPWithFSTMD(_vfp_d0_d15_pad); } return _vfp_d0_d15_pad[regNum - UNW_ARM_D0]; } else if (regNum >= UNW_ARM_D16 && regNum <= UNW_ARM_D31) { if (!_saved_vfp_d16_d31) { _saved_vfp_d16_d31 = true; saveVFPv3(_vfp_d16_d31); } return _vfp_d16_d31[regNum - UNW_ARM_D16]; } else if (regNum >= UNW_ARM_WR0 && regNum <= UNW_ARM_WR15) { if (!_saved_iwmmx) { _saved_iwmmx = true; saveiWMMX(_iwmmx); } return _iwmmx[regNum - UNW_ARM_WR0]; } else { _LIBUNWIND_ABORT("Unknown ARM float register"); } } inline void Registers_arm::setFloatRegister(int regNum, unw_fpreg_t value) { if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D15) { if (!_saved_vfp_d0_d15) { _saved_vfp_d0_d15 = true; if (_use_X_for_vfp_save) saveVFPWithFSTMX(_vfp_d0_d15_pad); else saveVFPWithFSTMD(_vfp_d0_d15_pad); } _vfp_d0_d15_pad[regNum - UNW_ARM_D0] = value; } else if (regNum >= UNW_ARM_D16 && regNum <= UNW_ARM_D31) { if (!_saved_vfp_d16_d31) { _saved_vfp_d16_d31 = true; saveVFPv3(_vfp_d16_d31); } _vfp_d16_d31[regNum - UNW_ARM_D16] = value; } else if (regNum >= UNW_ARM_WR0 && regNum <= UNW_ARM_WR15) { if (!_saved_iwmmx) { _saved_iwmmx = true; saveiWMMX(_iwmmx); } _iwmmx[regNum - UNW_ARM_WR0] = value; } else { _LIBUNWIND_ABORT("Unknown ARM float register"); } } inline bool Registers_arm::validVectorRegister(int) const { return false; } inline v128 Registers_arm::getVectorRegister(int) const { _LIBUNWIND_ABORT("ARM vector support not implemented"); } inline void Registers_arm::setVectorRegister(int, v128) { _LIBUNWIND_ABORT("ARM vector support not implemented"); } +#endif // _LIBUNWIND_TARGET_ARM + + +#if defined(_LIBUNWIND_TARGET_OR1K) /// Registers_or1k holds the register state of a thread in an OpenRISC1000 /// process. class _LIBUNWIND_HIDDEN Registers_or1k { public: Registers_or1k(); Registers_or1k(const void *registers); bool validRegister(int num) const; uint32_t getRegister(int num) const; void setRegister(int num, uint32_t value); bool validFloatRegister(int num) const; double getFloatRegister(int num) const; void setFloatRegister(int num, double value); bool validVectorRegister(int num) const; v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); const char *getRegisterName(int num); void jumpto(); static int lastDwarfRegNum() { return 31; } uint64_t getSP() const { return _registers.__r[1]; } void setSP(uint32_t value) { _registers.__r[1] = value; } uint64_t getIP() const { return _registers.__r[9]; } void setIP(uint32_t value) { _registers.__r[9] = value; } private: struct or1k_thread_state_t { unsigned int __r[32]; }; or1k_thread_state_t _registers; }; inline Registers_or1k::Registers_or1k(const void *registers) { - static_assert(sizeof(Registers_or1k) < sizeof(unw_context_t), - "or1k registers do not fit into unw_context_t"); + static_assert((check_fit::does_fit), + "or1k registers do not fit into unw_context_t"); memcpy(&_registers, static_cast(registers), sizeof(_registers)); } inline Registers_or1k::Registers_or1k() { memset(&_registers, 0, sizeof(_registers)); } inline bool Registers_or1k::validRegister(int regNum) const { if (regNum == UNW_REG_IP) return true; if (regNum == UNW_REG_SP) return true; if (regNum < 0) return false; if (regNum <= UNW_OR1K_R31) return true; return false; } inline uint32_t Registers_or1k::getRegister(int regNum) const { if (regNum >= UNW_OR1K_R0 && regNum <= UNW_OR1K_R31) return _registers.__r[regNum - UNW_OR1K_R0]; switch (regNum) { case UNW_REG_IP: return _registers.__r[9]; case UNW_REG_SP: return _registers.__r[1]; } _LIBUNWIND_ABORT("unsupported or1k register"); } inline void Registers_or1k::setRegister(int regNum, uint32_t value) { if (regNum >= UNW_OR1K_R0 && regNum <= UNW_OR1K_R31) { _registers.__r[regNum - UNW_OR1K_R0] = value; return; } switch (regNum) { case UNW_REG_IP: _registers.__r[9] = value; return; case UNW_REG_SP: _registers.__r[1] = value; return; } _LIBUNWIND_ABORT("unsupported or1k register"); } inline bool Registers_or1k::validFloatRegister(int /* regNum */) const { return false; } inline double Registers_or1k::getFloatRegister(int /* regNum */) const { _LIBUNWIND_ABORT("or1k float support not implemented"); } inline void Registers_or1k::setFloatRegister(int /* regNum */, double /* value */) { _LIBUNWIND_ABORT("or1k float support not implemented"); } inline bool Registers_or1k::validVectorRegister(int /* regNum */) const { return false; } inline v128 Registers_or1k::getVectorRegister(int /* regNum */) const { _LIBUNWIND_ABORT("or1k vector support not implemented"); } inline void Registers_or1k::setVectorRegister(int /* regNum */, v128 /* value */) { _LIBUNWIND_ABORT("or1k vector support not implemented"); } inline const char *Registers_or1k::getRegisterName(int regNum) { switch (regNum) { case UNW_OR1K_R0: return "r0"; case UNW_OR1K_R1: return "r1"; case UNW_OR1K_R2: return "r2"; case UNW_OR1K_R3: return "r3"; case UNW_OR1K_R4: return "r4"; case UNW_OR1K_R5: return "r5"; case UNW_OR1K_R6: return "r6"; case UNW_OR1K_R7: return "r7"; case UNW_OR1K_R8: return "r8"; case UNW_OR1K_R9: return "r9"; case UNW_OR1K_R10: return "r10"; case UNW_OR1K_R11: return "r11"; case UNW_OR1K_R12: return "r12"; case UNW_OR1K_R13: return "r13"; case UNW_OR1K_R14: return "r14"; case UNW_OR1K_R15: return "r15"; case UNW_OR1K_R16: return "r16"; case UNW_OR1K_R17: return "r17"; case UNW_OR1K_R18: return "r18"; case UNW_OR1K_R19: return "r19"; case UNW_OR1K_R20: return "r20"; case UNW_OR1K_R21: return "r21"; case UNW_OR1K_R22: return "r22"; case UNW_OR1K_R23: return "r23"; case UNW_OR1K_R24: return "r24"; case UNW_OR1K_R25: return "r25"; case UNW_OR1K_R26: return "r26"; case UNW_OR1K_R27: return "r27"; case UNW_OR1K_R28: return "r28"; case UNW_OR1K_R29: return "r29"; case UNW_OR1K_R30: return "r30"; case UNW_OR1K_R31: return "r31"; default: return "unknown register"; } } +#endif // _LIBUNWIND_TARGET_OR1K + + +#if defined(_LIBUNWIND_TARGET_RISCV) +/// Registers_riscv holds the register state of a thread in a 64-bit RISC-V +/// process. +class _LIBUNWIND_HIDDEN Registers_riscv { +public: + Registers_riscv(); + Registers_riscv(const void *registers); + + bool validRegister(int num) const; + uint64_t getRegister(int num) const; + void setRegister(int num, uint64_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + const char *getRegisterName(int num); + void jumpto(); + static int lastDwarfRegNum() { return 95; } + + uint64_t getSP() const { return _registers.__x[2]; } + void setSP(uint64_t value) { _registers.__x[2] = value; } + uint64_t getIP() const { return _registers.__x[1]; } + void setIP(uint64_t value) { _registers.__x[1] = value; } + +private: + struct GPRs { + uint64_t __x[32]; // x0-x31 + }; + + GPRs _registers; + double _vectorHalfRegisters[32]; + // Currently only the lower double in 128-bit vectore registers + // is perserved during unwinding. We could define new register + // numbers (> 96) which mean whole vector registers, then this + // struct would need to change to contain whole vector registers. +}; + +inline Registers_riscv::Registers_riscv(const void *registers) { + static_assert((check_fit::does_fit), + "riscv registers do not fit into unw_context_t"); + memcpy(&_registers, registers, sizeof(_registers)); + static_assert(sizeof(GPRs) == 0x100, + "expected VFP registers to be at offset 256"); + memcpy(_vectorHalfRegisters, + static_cast(registers) + sizeof(GPRs), + sizeof(_vectorHalfRegisters)); +} + +inline Registers_riscv::Registers_riscv() { + memset(&_registers, 0, sizeof(_registers)); + memset(&_vectorHalfRegisters, 0, sizeof(_vectorHalfRegisters)); +} + +inline bool Registers_riscv::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum < 0) + return false; + if (regNum > 95) + return false; + if ((regNum > 31) && (regNum < 64)) + return false; + return true; +} + +inline uint64_t Registers_riscv::getRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return _registers.__x[1]; + if (regNum == UNW_REG_SP) + return _registers.__x[2]; + if ((regNum >= 0) && (regNum < 32)) + return _registers.__x[regNum]; + _LIBUNWIND_ABORT("unsupported riscv register"); +} + +inline void Registers_riscv::setRegister(int regNum, uint64_t value) { + if (regNum == UNW_REG_IP) + _registers.__x[1] = value; + else if (regNum == UNW_REG_SP) + _registers.__x[2] = value; + else if ((regNum >= 0) && (regNum < 32)) + _registers.__x[regNum] = value; + else + _LIBUNWIND_ABORT("unsupported riscv register"); +} + +inline const char *Registers_riscv::getRegisterName(int regNum) { + switch (regNum) { + case UNW_REG_IP: + return "ra"; + case UNW_REG_SP: + return "sp"; + case UNW_RISCV_X0: + return "x0"; + case UNW_RISCV_X1: + return "ra"; + case UNW_RISCV_X2: + return "sp"; + case UNW_RISCV_X3: + return "x3"; + case UNW_RISCV_X4: + return "x4"; + case UNW_RISCV_X5: + return "x5"; + case UNW_RISCV_X6: + return "x6"; + case UNW_RISCV_X7: + return "x7"; + case UNW_RISCV_X8: + return "x8"; + case UNW_RISCV_X9: + return "x9"; + case UNW_RISCV_X10: + return "x10"; + case UNW_RISCV_X11: + return "x11"; + case UNW_RISCV_X12: + return "x12"; + case UNW_RISCV_X13: + return "x13"; + case UNW_RISCV_X14: + return "x14"; + case UNW_RISCV_X15: + return "x15"; + case UNW_RISCV_X16: + return "x16"; + case UNW_RISCV_X17: + return "x17"; + case UNW_RISCV_X18: + return "x18"; + case UNW_RISCV_X19: + return "x19"; + case UNW_RISCV_X20: + return "x20"; + case UNW_RISCV_X21: + return "x21"; + case UNW_RISCV_X22: + return "x22"; + case UNW_RISCV_X23: + return "x23"; + case UNW_RISCV_X24: + return "x24"; + case UNW_RISCV_X25: + return "x25"; + case UNW_RISCV_X26: + return "x26"; + case UNW_RISCV_X27: + return "x27"; + case UNW_RISCV_X28: + return "x28"; + case UNW_RISCV_X29: + return "x29"; + case UNW_RISCV_X30: + return "x30"; + case UNW_RISCV_X31: + return "x31"; + case UNW_RISCV_D0: + return "d0"; + case UNW_RISCV_D1: + return "d1"; + case UNW_RISCV_D2: + return "d2"; + case UNW_RISCV_D3: + return "d3"; + case UNW_RISCV_D4: + return "d4"; + case UNW_RISCV_D5: + return "d5"; + case UNW_RISCV_D6: + return "d6"; + case UNW_RISCV_D7: + return "d7"; + case UNW_RISCV_D8: + return "d8"; + case UNW_RISCV_D9: + return "d9"; + case UNW_RISCV_D10: + return "d10"; + case UNW_RISCV_D11: + return "d11"; + case UNW_RISCV_D12: + return "d12"; + case UNW_RISCV_D13: + return "d13"; + case UNW_RISCV_D14: + return "d14"; + case UNW_RISCV_D15: + return "d15"; + case UNW_RISCV_D16: + return "d16"; + case UNW_RISCV_D17: + return "d17"; + case UNW_RISCV_D18: + return "d18"; + case UNW_RISCV_D19: + return "d19"; + case UNW_RISCV_D20: + return "d20"; + case UNW_RISCV_D21: + return "d21"; + case UNW_RISCV_D22: + return "d22"; + case UNW_RISCV_D23: + return "d23"; + case UNW_RISCV_D24: + return "d24"; + case UNW_RISCV_D25: + return "d25"; + case UNW_RISCV_D26: + return "d26"; + case UNW_RISCV_D27: + return "d27"; + case UNW_RISCV_D28: + return "d28"; + case UNW_RISCV_D29: + return "d29"; + case UNW_RISCV_D30: + return "d30"; + case UNW_RISCV_D31: + return "d31"; + default: + return "unknown register"; + } +} + +inline bool Registers_riscv::validFloatRegister(int regNum) const { + if (regNum < UNW_RISCV_D0) + return false; + if (regNum > UNW_RISCV_D31) + return false; + return true; +} + +inline double Registers_riscv::getFloatRegister(int regNum) const { + assert(validFloatRegister(regNum)); + return _vectorHalfRegisters[regNum - UNW_RISCV_D0]; +} + +inline void Registers_riscv::setFloatRegister(int regNum, double value) { + assert(validFloatRegister(regNum)); + _vectorHalfRegisters[regNum - UNW_RISCV_D0] = value; +} + +inline bool Registers_riscv::validVectorRegister(int) const { + return false; +} + +inline v128 Registers_riscv::getVectorRegister(int) const { + _LIBUNWIND_ABORT("no riscv vector register support yet"); +} + +inline void Registers_riscv::setVectorRegister(int, v128) { + _LIBUNWIND_ABORT("no riscv vector register support yet"); +} +#endif // _LIBUNWIND_TARGET_RISCV } // namespace libunwind #endif // __REGISTERS_HPP__ Index: head/contrib/llvm/projects/libunwind/src/Unwind-EHABI.cpp =================================================================== --- head/contrib/llvm/projects/libunwind/src/Unwind-EHABI.cpp (revision 302449) +++ head/contrib/llvm/projects/libunwind/src/Unwind-EHABI.cpp (revision 302450) @@ -1,1009 +1,977 @@ //===--------------------------- Unwind-EHABI.cpp -------------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // // // Implements ARM zero-cost C++ exceptions // //===----------------------------------------------------------------------===// #include "Unwind-EHABI.h" #if _LIBUNWIND_ARM_EHABI #include #include #include #include #include #include #include "config.h" #include "libunwind.h" #include "libunwind_ext.h" #include "unwind.h" namespace { // Strange order: take words in order, but inside word, take from most to least // signinficant byte. uint8_t getByte(const uint32_t* data, size_t offset) { const uint8_t* byteData = reinterpret_cast(data); return byteData[(offset & ~(size_t)0x03) + (3 - (offset & (size_t)0x03))]; } const char* getNextWord(const char* data, uint32_t* out) { *out = *reinterpret_cast(data); return data + 4; } const char* getNextNibble(const char* data, uint32_t* out) { *out = *reinterpret_cast(data); return data + 2; } struct Descriptor { // See # 9.2 typedef enum { SU16 = 0, // Short descriptor, 16-bit entries LU16 = 1, // Long descriptor, 16-bit entries LU32 = 3, // Long descriptor, 32-bit entries RESERVED0 = 4, RESERVED1 = 5, RESERVED2 = 6, RESERVED3 = 7, RESERVED4 = 8, RESERVED5 = 9, RESERVED6 = 10, RESERVED7 = 11, RESERVED8 = 12, RESERVED9 = 13, RESERVED10 = 14, RESERVED11 = 15 } Format; // See # 9.2 typedef enum { CLEANUP = 0x0, FUNC = 0x1, CATCH = 0x2, INVALID = 0x4 } Kind; }; _Unwind_Reason_Code ProcessDescriptors( _Unwind_State state, _Unwind_Control_Block* ucbp, struct _Unwind_Context* context, Descriptor::Format format, const char* descriptorStart, uint32_t flags) { // EHT is inlined in the index using compact form. No descriptors. #5 if (flags & 0x1) return _URC_CONTINUE_UNWIND; // TODO: We should check the state here, and determine whether we need to // perform phase1 or phase2 unwinding. (void)state; const char* descriptor = descriptorStart; uint32_t descriptorWord; getNextWord(descriptor, &descriptorWord); while (descriptorWord) { // Read descriptor based on # 9.2. uint32_t length; uint32_t offset; switch (format) { case Descriptor::LU32: descriptor = getNextWord(descriptor, &length); descriptor = getNextWord(descriptor, &offset); case Descriptor::LU16: descriptor = getNextNibble(descriptor, &length); descriptor = getNextNibble(descriptor, &offset); default: assert(false); return _URC_FAILURE; } // See # 9.2 table for decoding the kind of descriptor. It's a 2-bit value. Descriptor::Kind kind = static_cast((length & 0x1) | ((offset & 0x1) << 1)); // Clear off flag from last bit. length &= ~1u; offset &= ~1u; uintptr_t scopeStart = ucbp->pr_cache.fnstart + offset; uintptr_t scopeEnd = scopeStart + length; uintptr_t pc = _Unwind_GetIP(context); bool isInScope = (scopeStart <= pc) && (pc < scopeEnd); switch (kind) { case Descriptor::CLEANUP: { // TODO(ajwong): Handle cleanup descriptors. break; } case Descriptor::FUNC: { // TODO(ajwong): Handle function descriptors. break; } case Descriptor::CATCH: { // Catch descriptors require gobbling one more word. uint32_t landing_pad; descriptor = getNextWord(descriptor, &landing_pad); if (isInScope) { // TODO(ajwong): This is only phase1 compatible logic. Implement // phase2. landing_pad = signExtendPrel31(landing_pad & ~0x80000000); if (landing_pad == 0xffffffff) { return _URC_HANDLER_FOUND; } else if (landing_pad == 0xfffffffe) { return _URC_FAILURE; } else { /* bool is_reference_type = landing_pad & 0x80000000; void* matched_object; if (__cxxabiv1::__cxa_type_match( ucbp, reinterpret_cast(landing_pad), is_reference_type, &matched_object) != __cxxabiv1::ctm_failed) return _URC_HANDLER_FOUND; */ _LIBUNWIND_ABORT("Type matching not implemented"); } } break; } default: _LIBUNWIND_ABORT("Invalid descriptor kind found."); } getNextWord(descriptor, &descriptorWord); } return _URC_CONTINUE_UNWIND; } static _Unwind_Reason_Code unwindOneFrame(_Unwind_State state, _Unwind_Control_Block* ucbp, struct _Unwind_Context* context) { // Read the compact model EHT entry's header # 6.3 const uint32_t* unwindingData = ucbp->pr_cache.ehtp; assert((*unwindingData & 0xf0000000) == 0x80000000 && "Must be a compact entry"); Descriptor::Format format = static_cast((*unwindingData & 0x0f000000) >> 24); const char *lsda = reinterpret_cast(_Unwind_GetLanguageSpecificData(context)); // Handle descriptors before unwinding so they are processed in the context // of the correct stack frame. _Unwind_Reason_Code result = ProcessDescriptors(state, ucbp, context, format, lsda, ucbp->pr_cache.additional); if (result != _URC_CONTINUE_UNWIND) return result; if (unw_step(reinterpret_cast(context)) != UNW_STEP_SUCCESS) return _URC_FAILURE; return _URC_CONTINUE_UNWIND; } // Generates mask discriminator for _Unwind_VRS_Pop, e.g. for _UVRSC_CORE / // _UVRSD_UINT32. uint32_t RegisterMask(uint8_t start, uint8_t count_minus_one) { return ((1U << (count_minus_one + 1)) - 1) << start; } // Generates mask discriminator for _Unwind_VRS_Pop, e.g. for _UVRSC_VFP / // _UVRSD_DOUBLE. uint32_t RegisterRange(uint8_t start, uint8_t count_minus_one) { return ((uint32_t)start << 16) | ((uint32_t)count_minus_one + 1); } } // end anonymous namespace /** * Decodes an EHT entry. * * @param data Pointer to EHT. * @param[out] off Offset from return value (in bytes) to begin interpretation. * @param[out] len Number of bytes in unwind code. * @return Pointer to beginning of unwind code. */ extern "C" const uint32_t* decode_eht_entry(const uint32_t* data, size_t* off, size_t* len) { if ((*data & 0x80000000) == 0) { // 6.2: Generic Model // // EHT entry is a prel31 pointing to the PR, followed by data understood // only by the personality routine. Fortunately, all existing assembler // implementations, including GNU assembler, LLVM integrated assembler, // and ARM assembler, assume that the unwind opcodes come after the // personality rountine address. *off = 1; // First byte is size data. *len = (((data[1] >> 24) & 0xff) + 1) * 4; data++; // Skip the first word, which is the prel31 offset. } else { // 6.3: ARM Compact Model // // EHT entries here correspond to the __aeabi_unwind_cpp_pr[012] PRs indeded // by format: Descriptor::Format format = static_cast((*data & 0x0f000000) >> 24); switch (format) { case Descriptor::SU16: *len = 4; *off = 1; break; case Descriptor::LU16: case Descriptor::LU32: *len = 4 + 4 * ((*data & 0x00ff0000) >> 16); *off = 2; break; default: return nullptr; } } return data; } _Unwind_Reason_Code _Unwind_VRS_Interpret( _Unwind_Context* context, const uint32_t* data, size_t offset, size_t len) { bool wrotePC = false; bool finish = false; while (offset < len && !finish) { uint8_t byte = getByte(data, offset++); if ((byte & 0x80) == 0) { uint32_t sp; _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp); if (byte & 0x40) sp -= (((uint32_t)byte & 0x3f) << 2) + 4; else sp += ((uint32_t)byte << 2) + 4; _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp); } else { switch (byte & 0xf0) { case 0x80: { if (offset >= len) return _URC_FAILURE; uint32_t registers = (((uint32_t)byte & 0x0f) << 12) | (((uint32_t)getByte(data, offset++)) << 4); if (!registers) return _URC_FAILURE; if (registers & (1 << 15)) wrotePC = true; _Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32); break; } case 0x90: { uint8_t reg = byte & 0x0f; if (reg == 13 || reg == 15) return _URC_FAILURE; uint32_t sp; _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_R0 + reg, _UVRSD_UINT32, &sp); _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp); break; } case 0xa0: { uint32_t registers = RegisterMask(4, byte & 0x07); if (byte & 0x08) registers |= 1 << 14; _Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32); break; } case 0xb0: { switch (byte) { case 0xb0: finish = true; break; case 0xb1: { if (offset >= len) return _URC_FAILURE; uint8_t registers = getByte(data, offset++); if (registers & 0xf0 || !registers) return _URC_FAILURE; _Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32); break; } case 0xb2: { uint32_t addend = 0; uint32_t shift = 0; // This decodes a uleb128 value. while (true) { if (offset >= len) return _URC_FAILURE; uint32_t v = getByte(data, offset++); addend |= (v & 0x7f) << shift; if ((v & 0x80) == 0) break; shift += 7; } uint32_t sp; _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp); sp += 0x204 + (addend << 2); _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp); break; } case 0xb3: { uint8_t v = getByte(data, offset++); _Unwind_VRS_Pop(context, _UVRSC_VFP, RegisterRange(static_cast(v >> 4), v & 0x0f), _UVRSD_VFPX); break; } case 0xb4: case 0xb5: case 0xb6: case 0xb7: return _URC_FAILURE; default: _Unwind_VRS_Pop(context, _UVRSC_VFP, RegisterRange(8, byte & 0x07), _UVRSD_VFPX); break; } break; } case 0xc0: { switch (byte) { case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: _Unwind_VRS_Pop(context, _UVRSC_WMMXD, RegisterRange(10, byte & 0x7), _UVRSD_DOUBLE); break; case 0xc6: { uint8_t v = getByte(data, offset++); uint8_t start = static_cast(v >> 4); uint8_t count_minus_one = v & 0xf; if (start + count_minus_one >= 16) return _URC_FAILURE; _Unwind_VRS_Pop(context, _UVRSC_WMMXD, RegisterRange(start, count_minus_one), _UVRSD_DOUBLE); break; } case 0xc7: { uint8_t v = getByte(data, offset++); if (!v || v & 0xf0) return _URC_FAILURE; _Unwind_VRS_Pop(context, _UVRSC_WMMXC, v, _UVRSD_DOUBLE); break; } case 0xc8: case 0xc9: { uint8_t v = getByte(data, offset++); uint8_t start = static_cast(((byte == 0xc8) ? 16 : 0) + (v >> 4)); uint8_t count_minus_one = v & 0xf; if (start + count_minus_one >= 32) return _URC_FAILURE; _Unwind_VRS_Pop(context, _UVRSC_VFP, RegisterRange(start, count_minus_one), _UVRSD_DOUBLE); break; } default: return _URC_FAILURE; } break; } case 0xd0: { if (byte & 0x08) return _URC_FAILURE; _Unwind_VRS_Pop(context, _UVRSC_VFP, RegisterRange(8, byte & 0x7), _UVRSD_DOUBLE); break; } default: return _URC_FAILURE; } } } if (!wrotePC) { uint32_t lr; _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_LR, _UVRSD_UINT32, &lr); _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_IP, _UVRSD_UINT32, &lr); } return _URC_CONTINUE_UNWIND; } extern "C" _Unwind_Reason_Code __aeabi_unwind_cpp_pr0( _Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context) { return unwindOneFrame(state, ucbp, context); } extern "C" _Unwind_Reason_Code __aeabi_unwind_cpp_pr1( _Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context) { return unwindOneFrame(state, ucbp, context); } extern "C" _Unwind_Reason_Code __aeabi_unwind_cpp_pr2( _Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context) { return unwindOneFrame(state, ucbp, context); } static _Unwind_Reason_Code -unwind_phase1(unw_context_t *uc, _Unwind_Exception *exception_object) { +unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) { // EHABI #7.3 discusses preserving the VRS in a "temporary VRS" during // phase 1 and then restoring it to the "primary VRS" for phase 2. The // effect is phase 2 doesn't see any of the VRS manipulations from phase 1. // In this implementation, the phases don't share the VRS backing store. // Instead, they are passed the original |uc| and they create a new VRS // from scratch thus achieving the same effect. - unw_cursor_t cursor1; - unw_init_local(&cursor1, uc); + unw_init_local(cursor, uc); // Walk each frame looking for a place to stop. for (bool handlerNotFound = true; handlerNotFound;) { -#if !_LIBUNWIND_ARM_EHABI - // Ask libuwind to get next frame (skip over first which is - // _Unwind_RaiseException). - int stepResult = unw_step(&cursor1); - if (stepResult == 0) { - _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step() reached " - "bottom => _URC_END_OF_STACK\n", - static_cast(exception_object)); - return _URC_END_OF_STACK; - } else if (stepResult < 0) { - _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step failed => " - "_URC_FATAL_PHASE1_ERROR\n", - static_cast(exception_object)); - return _URC_FATAL_PHASE1_ERROR; - } -#endif - // See if frame has code to run (has personality routine). unw_proc_info_t frameInfo; - if (unw_get_proc_info(&cursor1, &frameInfo) != UNW_ESUCCESS) { + if (unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_get_proc_info " "failed => _URC_FATAL_PHASE1_ERROR\n", static_cast(exception_object)); return _URC_FATAL_PHASE1_ERROR; } // When tracing, print state information. if (_LIBUNWIND_TRACING_UNWINDING) { char functionBuf[512]; const char *functionName = functionBuf; unw_word_t offset; - if ((unw_get_proc_name(&cursor1, functionBuf, sizeof(functionBuf), + if ((unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), &offset) != UNW_ESUCCESS) || (frameInfo.start_ip + offset > frameInfo.end_ip)) functionName = ".anonymous."; unw_word_t pc; - unw_get_reg(&cursor1, UNW_REG_IP, &pc); + unw_get_reg(cursor, UNW_REG_IP, &pc); _LIBUNWIND_TRACE_UNWINDING( "unwind_phase1(ex_ojb=%p): pc=0x%llX, start_ip=0x%llX, func=%s, " "lsda=0x%llX, personality=0x%llX\n", static_cast(exception_object), (long long)pc, (long long)frameInfo.start_ip, functionName, (long long)frameInfo.lsda, (long long)frameInfo.handler); } // If there is a personality routine, ask it if it will want to stop at // this frame. if (frameInfo.handler != 0) { __personality_routine p = (__personality_routine)(long)(frameInfo.handler); _LIBUNWIND_TRACE_UNWINDING( "unwind_phase1(ex_ojb=%p): calling personality function %p\n", static_cast(exception_object), reinterpret_cast(reinterpret_cast(p))); - struct _Unwind_Context *context = (struct _Unwind_Context *)(&cursor1); + struct _Unwind_Context *context = (struct _Unwind_Context *)(cursor); exception_object->pr_cache.fnstart = frameInfo.start_ip; exception_object->pr_cache.ehtp = (_Unwind_EHT_Header *)frameInfo.unwind_info; exception_object->pr_cache.additional = frameInfo.flags; _Unwind_Reason_Code personalityResult = (*p)(_US_VIRTUAL_UNWIND_FRAME, exception_object, context); _LIBUNWIND_TRACE_UNWINDING( "unwind_phase1(ex_ojb=%p): personality result %d start_ip %x ehtp %p " "additional %x\n", static_cast(exception_object), personalityResult, exception_object->pr_cache.fnstart, static_cast(exception_object->pr_cache.ehtp), exception_object->pr_cache.additional); switch (personalityResult) { case _URC_HANDLER_FOUND: // found a catch clause or locals that need destructing in this frame // stop search and remember stack pointer at the frame handlerNotFound = false; // p should have initialized barrier_cache. EHABI #7.3.5 _LIBUNWIND_TRACE_UNWINDING( "unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND \n", static_cast(exception_object)); return _URC_NO_REASON; case _URC_CONTINUE_UNWIND: _LIBUNWIND_TRACE_UNWINDING( "unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", static_cast(exception_object)); // continue unwinding break; // EHABI #7.3.3 case _URC_FAILURE: return _URC_FAILURE; default: // something went wrong _LIBUNWIND_TRACE_UNWINDING( "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n", static_cast(exception_object)); return _URC_FATAL_PHASE1_ERROR; } } } return _URC_NO_REASON; } -static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, +static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object, bool resume) { // See comment at the start of unwind_phase1 regarding VRS integrity. - unw_cursor_t cursor2; - unw_init_local(&cursor2, uc); + unw_init_local(cursor, uc); _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)\n", static_cast(exception_object)); int frame_count = 0; // Walk each frame until we reach where search phase said to stop. while (true) { // Ask libuwind to get next frame (skip over first which is // _Unwind_RaiseException or _Unwind_Resume). // // Resume only ever makes sense for 1 frame. _Unwind_State state = resume ? _US_UNWIND_FRAME_RESUME : _US_UNWIND_FRAME_STARTING; if (resume && frame_count == 1) { // On a resume, first unwind the _Unwind_Resume() frame. The next frame // is now the landing pad for the cleanup from a previous execution of // phase2. To continue unwindingly correctly, replace VRS[15] with the // IP of the frame that the previous run of phase2 installed the context // for. After this, continue unwinding as if normal. // // See #7.4.6 for details. - unw_set_reg(&cursor2, UNW_REG_IP, + unw_set_reg(cursor, UNW_REG_IP, exception_object->unwinder_cache.reserved2); resume = false; } -#if !_LIBUNWIND_ARM_EHABI - int stepResult = unw_step(&cursor2); - if (stepResult == 0) { - _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached " - "bottom => _URC_END_OF_STACK\n", - static_cast(exception_object)); - return _URC_END_OF_STACK; - } else if (stepResult < 0) { - _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step failed => " - "_URC_FATAL_PHASE1_ERROR\n", - static_cast(exception_object)); - return _URC_FATAL_PHASE2_ERROR; - } -#endif - // Get info about this frame. unw_word_t sp; unw_proc_info_t frameInfo; - unw_get_reg(&cursor2, UNW_REG_SP, &sp); - if (unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) { + unw_get_reg(cursor, UNW_REG_SP, &sp); + if (unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_get_proc_info " "failed => _URC_FATAL_PHASE1_ERROR\n", static_cast(exception_object)); return _URC_FATAL_PHASE2_ERROR; } // When tracing, print state information. if (_LIBUNWIND_TRACING_UNWINDING) { char functionBuf[512]; const char *functionName = functionBuf; unw_word_t offset; - if ((unw_get_proc_name(&cursor2, functionBuf, sizeof(functionBuf), + if ((unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), &offset) != UNW_ESUCCESS) || (frameInfo.start_ip + offset > frameInfo.end_ip)) functionName = ".anonymous."; _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2(ex_ojb=%p): start_ip=0x%llX, func=%s, sp=0x%llX, " "lsda=0x%llX, personality=0x%llX\n", static_cast(exception_object), (long long)frameInfo.start_ip, functionName, (long long)sp, (long long)frameInfo.lsda, (long long)frameInfo.handler); } // If there is a personality routine, tell it we are unwinding. if (frameInfo.handler != 0) { __personality_routine p = (__personality_routine)(long)(frameInfo.handler); - struct _Unwind_Context *context = (struct _Unwind_Context *)(&cursor2); + struct _Unwind_Context *context = (struct _Unwind_Context *)(cursor); // EHABI #7.2 exception_object->pr_cache.fnstart = frameInfo.start_ip; exception_object->pr_cache.ehtp = (_Unwind_EHT_Header *)frameInfo.unwind_info; exception_object->pr_cache.additional = frameInfo.flags; _Unwind_Reason_Code personalityResult = (*p)(state, exception_object, context); switch (personalityResult) { case _URC_CONTINUE_UNWIND: // Continue unwinding _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", static_cast(exception_object)); // EHABI #7.2 if (sp == exception_object->barrier_cache.sp) { // Phase 1 said we would stop at this frame, but we did not... _LIBUNWIND_ABORT("during phase1 personality function said it would " "stop here, but now in phase2 it did not stop here"); } break; case _URC_INSTALL_CONTEXT: _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT\n", static_cast(exception_object)); // Personality routine says to transfer control to landing pad. // We may get control back if landing pad calls _Unwind_Resume(). if (_LIBUNWIND_TRACING_UNWINDING) { unw_word_t pc; - unw_get_reg(&cursor2, UNW_REG_IP, &pc); - unw_get_reg(&cursor2, UNW_REG_SP, &sp); + unw_get_reg(cursor, UNW_REG_IP, &pc); + unw_get_reg(cursor, UNW_REG_SP, &sp); _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering " "user code with ip=0x%llX, sp=0x%llX\n", static_cast(exception_object), (long long)pc, (long long)sp); } { // EHABI #7.4.1 says we need to preserve pc for when _Unwind_Resume // is called back, to find this same frame. unw_word_t pc; - unw_get_reg(&cursor2, UNW_REG_IP, &pc); + unw_get_reg(cursor, UNW_REG_IP, &pc); exception_object->unwinder_cache.reserved2 = (uint32_t)pc; } - unw_resume(&cursor2); + unw_resume(cursor); // unw_resume() only returns if there was an error. return _URC_FATAL_PHASE2_ERROR; // # EHABI #7.4.3 case _URC_FAILURE: abort(); default: // Personality routine returned an unknown result code. _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d", personalityResult); return _URC_FATAL_PHASE2_ERROR; } } frame_count++; } // Clean up phase did not resume at the frame that the search phase // said it would... return _URC_FATAL_PHASE2_ERROR; } /// Called by __cxa_throw. Only returns if there is a fatal error. _LIBUNWIND_EXPORT _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception *exception_object) { _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)\n", static_cast(exception_object)); unw_context_t uc; + unw_cursor_t cursor; unw_getcontext(&uc); // This field for is for compatibility with GCC to say this isn't a forced // unwind. EHABI #7.2 exception_object->unwinder_cache.reserved1 = 0; // phase 1: the search phase - _Unwind_Reason_Code phase1 = unwind_phase1(&uc, exception_object); + _Unwind_Reason_Code phase1 = unwind_phase1(&uc, &cursor, exception_object); if (phase1 != _URC_NO_REASON) return phase1; // phase 2: the clean up phase - return unwind_phase2(&uc, exception_object, false); + return unwind_phase2(&uc, &cursor, exception_object, false); } _LIBUNWIND_EXPORT void _Unwind_Complete(_Unwind_Exception* exception_object) { // This is to be called when exception handling completes to give us a chance // to perform any housekeeping. EHABI #7.2. But we have nothing to do here. (void)exception_object; } /// When _Unwind_RaiseException() is in phase2, it hands control /// to the personality function at each frame. The personality /// may force a jump to a landing pad in that function, the landing /// pad code may then call _Unwind_Resume() to continue with the /// unwinding. Note: the call to _Unwind_Resume() is from compiler /// geneated user code. All other _Unwind_* routines are called /// by the C++ runtime __cxa_* routines. /// /// Note: re-throwing an exception (as opposed to continuing the unwind) /// is implemented by having the code call __cxa_rethrow() which /// in turn calls _Unwind_Resume_or_Rethrow(). _LIBUNWIND_EXPORT void _Unwind_Resume(_Unwind_Exception *exception_object) { _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)\n", static_cast(exception_object)); unw_context_t uc; + unw_cursor_t cursor; unw_getcontext(&uc); // _Unwind_RaiseException on EHABI will always set the reserved1 field to 0, // which is in the same position as private_1 below. // TODO(ajwong): Who wronte the above? Why is it true? - unwind_phase2(&uc, exception_object, true); + unwind_phase2(&uc, &cursor, exception_object, true); // Clients assume _Unwind_Resume() does not return, so all we can do is abort. _LIBUNWIND_ABORT("_Unwind_Resume() can't return"); } /// Called by personality handler during phase 2 to get LSDA for current frame. _LIBUNWIND_EXPORT uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { unw_cursor_t *cursor = (unw_cursor_t *)context; unw_proc_info_t frameInfo; uintptr_t result = 0; if (unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) result = (uintptr_t)frameInfo.lsda; _LIBUNWIND_TRACE_API( "_Unwind_GetLanguageSpecificData(context=%p) => 0x%llx\n", static_cast(context), (long long)result); return result; } static uint64_t ValueAsBitPattern(_Unwind_VRS_DataRepresentation representation, void* valuep) { uint64_t value = 0; switch (representation) { case _UVRSD_UINT32: case _UVRSD_FLOAT: memcpy(&value, valuep, sizeof(uint32_t)); break; case _UVRSD_VFPX: case _UVRSD_UINT64: case _UVRSD_DOUBLE: memcpy(&value, valuep, sizeof(uint64_t)); break; } return value; } _Unwind_VRS_Result _Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, uint32_t regno, _Unwind_VRS_DataRepresentation representation, void *valuep) { _LIBUNWIND_TRACE_API("_Unwind_VRS_Set(context=%p, regclass=%d, reg=%d, " "rep=%d, value=0x%llX)\n", static_cast(context), regclass, regno, representation, ValueAsBitPattern(representation, valuep)); unw_cursor_t *cursor = (unw_cursor_t *)context; switch (regclass) { case _UVRSC_CORE: if (representation != _UVRSD_UINT32 || regno > 15) return _UVRSR_FAILED; return unw_set_reg(cursor, (unw_regnum_t)(UNW_ARM_R0 + regno), *(unw_word_t *)valuep) == UNW_ESUCCESS ? _UVRSR_OK : _UVRSR_FAILED; case _UVRSC_WMMXC: if (representation != _UVRSD_UINT32 || regno > 3) return _UVRSR_FAILED; return unw_set_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno), *(unw_word_t *)valuep) == UNW_ESUCCESS ? _UVRSR_OK : _UVRSR_FAILED; case _UVRSC_VFP: if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) return _UVRSR_FAILED; if (representation == _UVRSD_VFPX) { // Can only touch d0-15 with FSTMFDX. if (regno > 15) return _UVRSR_FAILED; unw_save_vfp_as_X(cursor); } else { if (regno > 31) return _UVRSR_FAILED; } return unw_set_fpreg(cursor, (unw_regnum_t)(UNW_ARM_D0 + regno), *(unw_fpreg_t *)valuep) == UNW_ESUCCESS ? _UVRSR_OK : _UVRSR_FAILED; case _UVRSC_WMMXD: if (representation != _UVRSD_DOUBLE || regno > 31) return _UVRSR_FAILED; return unw_set_fpreg(cursor, (unw_regnum_t)(UNW_ARM_WR0 + regno), *(unw_fpreg_t *)valuep) == UNW_ESUCCESS ? _UVRSR_OK : _UVRSR_FAILED; } _LIBUNWIND_ABORT("unsupported register class"); } static _Unwind_VRS_Result _Unwind_VRS_Get_Internal(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, uint32_t regno, _Unwind_VRS_DataRepresentation representation, void *valuep) { unw_cursor_t *cursor = (unw_cursor_t *)context; switch (regclass) { case _UVRSC_CORE: if (representation != _UVRSD_UINT32 || regno > 15) return _UVRSR_FAILED; return unw_get_reg(cursor, (unw_regnum_t)(UNW_ARM_R0 + regno), (unw_word_t *)valuep) == UNW_ESUCCESS ? _UVRSR_OK : _UVRSR_FAILED; case _UVRSC_WMMXC: if (representation != _UVRSD_UINT32 || regno > 3) return _UVRSR_FAILED; return unw_get_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno), (unw_word_t *)valuep) == UNW_ESUCCESS ? _UVRSR_OK : _UVRSR_FAILED; case _UVRSC_VFP: if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) return _UVRSR_FAILED; if (representation == _UVRSD_VFPX) { // Can only touch d0-15 with FSTMFDX. if (regno > 15) return _UVRSR_FAILED; unw_save_vfp_as_X(cursor); } else { if (regno > 31) return _UVRSR_FAILED; } return unw_get_fpreg(cursor, (unw_regnum_t)(UNW_ARM_D0 + regno), (unw_fpreg_t *)valuep) == UNW_ESUCCESS ? _UVRSR_OK : _UVRSR_FAILED; case _UVRSC_WMMXD: if (representation != _UVRSD_DOUBLE || regno > 31) return _UVRSR_FAILED; return unw_get_fpreg(cursor, (unw_regnum_t)(UNW_ARM_WR0 + regno), (unw_fpreg_t *)valuep) == UNW_ESUCCESS ? _UVRSR_OK : _UVRSR_FAILED; } _LIBUNWIND_ABORT("unsupported register class"); } _Unwind_VRS_Result _Unwind_VRS_Get( _Unwind_Context *context, _Unwind_VRS_RegClass regclass, uint32_t regno, _Unwind_VRS_DataRepresentation representation, void *valuep) { _Unwind_VRS_Result result = _Unwind_VRS_Get_Internal(context, regclass, regno, representation, valuep); _LIBUNWIND_TRACE_API("_Unwind_VRS_Get(context=%p, regclass=%d, reg=%d, " "rep=%d, value=0x%llX, result = %d)\n", static_cast(context), regclass, regno, representation, ValueAsBitPattern(representation, valuep), result); return result; } _Unwind_VRS_Result _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, uint32_t discriminator, _Unwind_VRS_DataRepresentation representation) { _LIBUNWIND_TRACE_API("_Unwind_VRS_Pop(context=%p, regclass=%d, " "discriminator=%d, representation=%d)\n", static_cast(context), regclass, discriminator, representation); switch (regclass) { case _UVRSC_CORE: case _UVRSC_WMMXC: { if (representation != _UVRSD_UINT32) return _UVRSR_FAILED; // When popping SP from the stack, we don't want to override it from the // computed new stack location. See EHABI #7.5.4 table 3. bool poppedSP = false; uint32_t* sp; if (_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp) != _UVRSR_OK) { return _UVRSR_FAILED; } for (uint32_t i = 0; i < 16; ++i) { if (!(discriminator & static_cast(1 << i))) continue; uint32_t value = *sp++; if (regclass == _UVRSC_CORE && i == 13) poppedSP = true; if (_Unwind_VRS_Set(context, regclass, i, _UVRSD_UINT32, &value) != _UVRSR_OK) { return _UVRSR_FAILED; } } if (!poppedSP) { return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp); } return _UVRSR_OK; } case _UVRSC_VFP: case _UVRSC_WMMXD: { if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) return _UVRSR_FAILED; uint32_t first = discriminator >> 16; uint32_t count = discriminator & 0xffff; uint32_t end = first+count; uint32_t* sp; if (_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp) != _UVRSR_OK) { return _UVRSR_FAILED; } // For _UVRSD_VFPX, we're assuming the data is stored in FSTMX "standard // format 1", which is equivalent to FSTMD + a padding word. for (uint32_t i = first; i < end; ++i) { // SP is only 32-bit aligned so don't copy 64-bit at a time. uint64_t value = *sp++; value |= ((uint64_t)(*sp++)) << 32; if (_Unwind_VRS_Set(context, regclass, i, representation, &value) != _UVRSR_OK) return _UVRSR_FAILED; } if (representation == _UVRSD_VFPX) ++sp; return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp); } } _LIBUNWIND_ABORT("unsupported register class"); } /// Called by personality handler during phase 2 to find the start of the /// function. _LIBUNWIND_EXPORT uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context *context) { unw_cursor_t *cursor = (unw_cursor_t *)context; unw_proc_info_t frameInfo; uintptr_t result = 0; if (unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) result = (uintptr_t)frameInfo.start_ip; _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%llX\n", static_cast(context), (long long)result); return result; } /// Called by personality handler during phase 2 if a foreign exception // is caught. _LIBUNWIND_EXPORT void _Unwind_DeleteException(_Unwind_Exception *exception_object) { _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)\n", static_cast(exception_object)); if (exception_object->exception_cleanup != NULL) (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, exception_object); } extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code __gnu_unwind_frame(_Unwind_Exception *exception_object, struct _Unwind_Context *context) { unw_cursor_t *cursor = (unw_cursor_t *)context; if (unw_step(cursor) != UNW_STEP_SUCCESS) return _URC_FAILURE; return _URC_OK; } #endif // _LIBUNWIND_ARM_EHABI Index: head/contrib/llvm/projects/libunwind/src/UnwindCursor.hpp =================================================================== --- head/contrib/llvm/projects/libunwind/src/UnwindCursor.hpp (revision 302449) +++ head/contrib/llvm/projects/libunwind/src/UnwindCursor.hpp (revision 302450) @@ -1,1344 +1,1372 @@ //===------------------------- UnwindCursor.hpp ---------------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // // // C++ interface to lower levels of libuwind //===----------------------------------------------------------------------===// #ifndef __UNWINDCURSOR_HPP__ #define __UNWINDCURSOR_HPP__ #include #include #include #include #include #include #ifdef __APPLE__ #include #endif #include "config.h" #include "AddressSpace.hpp" #include "CompactUnwinder.hpp" #include "config.h" #include "DwarfInstructions.hpp" #include "EHHeaderParser.hpp" #include "libunwind.h" #include "Registers.hpp" #include "Unwind-EHABI.h" namespace libunwind { #if _LIBUNWIND_SUPPORT_DWARF_UNWIND /// Cache of recently found FDEs. template class _LIBUNWIND_HIDDEN DwarfFDECache { typedef typename A::pint_t pint_t; public: static pint_t findFDE(pint_t mh, pint_t pc); static void add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde); static void removeAllIn(pint_t mh); static void iterateCacheEntries(void (*func)(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)); private: struct entry { pint_t mh; pint_t ip_start; pint_t ip_end; pint_t fde; }; // These fields are all static to avoid needing an initializer. // There is only one instance of this class per process. static pthread_rwlock_t _lock; #ifdef __APPLE__ static void dyldUnloadHook(const struct mach_header *mh, intptr_t slide); static bool _registeredForDyldUnloads; #endif // Can't use std::vector<> here because this code is below libc++. static entry *_buffer; static entry *_bufferUsed; static entry *_bufferEnd; static entry _initialBuffer[64]; }; template typename DwarfFDECache::entry * DwarfFDECache::_buffer = _initialBuffer; template typename DwarfFDECache::entry * DwarfFDECache::_bufferUsed = _initialBuffer; template typename DwarfFDECache::entry * DwarfFDECache::_bufferEnd = &_initialBuffer[64]; template typename DwarfFDECache::entry DwarfFDECache::_initialBuffer[64]; template pthread_rwlock_t DwarfFDECache::_lock = PTHREAD_RWLOCK_INITIALIZER; #ifdef __APPLE__ template bool DwarfFDECache::_registeredForDyldUnloads = false; #endif template typename A::pint_t DwarfFDECache::findFDE(pint_t mh, pint_t pc) { pint_t result = 0; _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_rdlock(&_lock)); for (entry *p = _buffer; p < _bufferUsed; ++p) { if ((mh == p->mh) || (mh == 0)) { if ((p->ip_start <= pc) && (pc < p->ip_end)) { result = p->fde; break; } } } _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock)); return result; } template void DwarfFDECache::add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde) { #if !defined(_LIBUNWIND_NO_HEAP) _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock)); if (_bufferUsed >= _bufferEnd) { size_t oldSize = (size_t)(_bufferEnd - _buffer); size_t newSize = oldSize * 4; // Can't use operator new (we are below it). entry *newBuffer = (entry *)malloc(newSize * sizeof(entry)); memcpy(newBuffer, _buffer, oldSize * sizeof(entry)); if (_buffer != _initialBuffer) free(_buffer); _buffer = newBuffer; _bufferUsed = &newBuffer[oldSize]; _bufferEnd = &newBuffer[newSize]; } _bufferUsed->mh = mh; _bufferUsed->ip_start = ip_start; _bufferUsed->ip_end = ip_end; _bufferUsed->fde = fde; ++_bufferUsed; #ifdef __APPLE__ if (!_registeredForDyldUnloads) { _dyld_register_func_for_remove_image(&dyldUnloadHook); _registeredForDyldUnloads = true; } #endif _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock)); #endif } template void DwarfFDECache::removeAllIn(pint_t mh) { _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock)); entry *d = _buffer; for (const entry *s = _buffer; s < _bufferUsed; ++s) { if (s->mh != mh) { if (d != s) *d = *s; ++d; } } _bufferUsed = d; _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock)); } #ifdef __APPLE__ template void DwarfFDECache::dyldUnloadHook(const struct mach_header *mh, intptr_t ) { removeAllIn((pint_t) mh); } #endif template void DwarfFDECache::iterateCacheEntries(void (*func)( unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) { _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock)); for (entry *p = _buffer; p < _bufferUsed; ++p) { (*func)(p->ip_start, p->ip_end, p->fde, p->mh); } _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock)); } #endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND #define arrayoffsetof(type, index, field) ((size_t)(&((type *)0)[index].field)) #if _LIBUNWIND_SUPPORT_COMPACT_UNWIND template class UnwindSectionHeader { public: UnwindSectionHeader(A &addressSpace, typename A::pint_t addr) : _addressSpace(addressSpace), _addr(addr) {} uint32_t version() const { return _addressSpace.get32(_addr + offsetof(unwind_info_section_header, version)); } uint32_t commonEncodingsArraySectionOffset() const { return _addressSpace.get32(_addr + offsetof(unwind_info_section_header, commonEncodingsArraySectionOffset)); } uint32_t commonEncodingsArrayCount() const { return _addressSpace.get32(_addr + offsetof(unwind_info_section_header, commonEncodingsArrayCount)); } uint32_t personalityArraySectionOffset() const { return _addressSpace.get32(_addr + offsetof(unwind_info_section_header, personalityArraySectionOffset)); } uint32_t personalityArrayCount() const { return _addressSpace.get32( _addr + offsetof(unwind_info_section_header, personalityArrayCount)); } uint32_t indexSectionOffset() const { return _addressSpace.get32( _addr + offsetof(unwind_info_section_header, indexSectionOffset)); } uint32_t indexCount() const { return _addressSpace.get32( _addr + offsetof(unwind_info_section_header, indexCount)); } private: A &_addressSpace; typename A::pint_t _addr; }; template class UnwindSectionIndexArray { public: UnwindSectionIndexArray(A &addressSpace, typename A::pint_t addr) : _addressSpace(addressSpace), _addr(addr) {} uint32_t functionOffset(uint32_t index) const { return _addressSpace.get32( _addr + arrayoffsetof(unwind_info_section_header_index_entry, index, functionOffset)); } uint32_t secondLevelPagesSectionOffset(uint32_t index) const { return _addressSpace.get32( _addr + arrayoffsetof(unwind_info_section_header_index_entry, index, secondLevelPagesSectionOffset)); } uint32_t lsdaIndexArraySectionOffset(uint32_t index) const { return _addressSpace.get32( _addr + arrayoffsetof(unwind_info_section_header_index_entry, index, lsdaIndexArraySectionOffset)); } private: A &_addressSpace; typename A::pint_t _addr; }; template class UnwindSectionRegularPageHeader { public: UnwindSectionRegularPageHeader(A &addressSpace, typename A::pint_t addr) : _addressSpace(addressSpace), _addr(addr) {} uint32_t kind() const { return _addressSpace.get32( _addr + offsetof(unwind_info_regular_second_level_page_header, kind)); } uint16_t entryPageOffset() const { return _addressSpace.get16( _addr + offsetof(unwind_info_regular_second_level_page_header, entryPageOffset)); } uint16_t entryCount() const { return _addressSpace.get16( _addr + offsetof(unwind_info_regular_second_level_page_header, entryCount)); } private: A &_addressSpace; typename A::pint_t _addr; }; template class UnwindSectionRegularArray { public: UnwindSectionRegularArray(A &addressSpace, typename A::pint_t addr) : _addressSpace(addressSpace), _addr(addr) {} uint32_t functionOffset(uint32_t index) const { return _addressSpace.get32( _addr + arrayoffsetof(unwind_info_regular_second_level_entry, index, functionOffset)); } uint32_t encoding(uint32_t index) const { return _addressSpace.get32( _addr + arrayoffsetof(unwind_info_regular_second_level_entry, index, encoding)); } private: A &_addressSpace; typename A::pint_t _addr; }; template class UnwindSectionCompressedPageHeader { public: UnwindSectionCompressedPageHeader(A &addressSpace, typename A::pint_t addr) : _addressSpace(addressSpace), _addr(addr) {} uint32_t kind() const { return _addressSpace.get32( _addr + offsetof(unwind_info_compressed_second_level_page_header, kind)); } uint16_t entryPageOffset() const { return _addressSpace.get16( _addr + offsetof(unwind_info_compressed_second_level_page_header, entryPageOffset)); } uint16_t entryCount() const { return _addressSpace.get16( _addr + offsetof(unwind_info_compressed_second_level_page_header, entryCount)); } uint16_t encodingsPageOffset() const { return _addressSpace.get16( _addr + offsetof(unwind_info_compressed_second_level_page_header, encodingsPageOffset)); } uint16_t encodingsCount() const { return _addressSpace.get16( _addr + offsetof(unwind_info_compressed_second_level_page_header, encodingsCount)); } private: A &_addressSpace; typename A::pint_t _addr; }; template class UnwindSectionCompressedArray { public: UnwindSectionCompressedArray(A &addressSpace, typename A::pint_t addr) : _addressSpace(addressSpace), _addr(addr) {} uint32_t functionOffset(uint32_t index) const { return UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET( _addressSpace.get32(_addr + index * sizeof(uint32_t))); } uint16_t encodingIndex(uint32_t index) const { return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX( _addressSpace.get32(_addr + index * sizeof(uint32_t))); } private: A &_addressSpace; typename A::pint_t _addr; }; template class UnwindSectionLsdaArray { public: UnwindSectionLsdaArray(A &addressSpace, typename A::pint_t addr) : _addressSpace(addressSpace), _addr(addr) {} uint32_t functionOffset(uint32_t index) const { return _addressSpace.get32( _addr + arrayoffsetof(unwind_info_section_header_lsda_index_entry, index, functionOffset)); } uint32_t lsdaOffset(uint32_t index) const { return _addressSpace.get32( _addr + arrayoffsetof(unwind_info_section_header_lsda_index_entry, index, lsdaOffset)); } private: A &_addressSpace; typename A::pint_t _addr; }; #endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND class _LIBUNWIND_HIDDEN AbstractUnwindCursor { public: // NOTE: provide a class specific placement deallocation function (S5.3.4 p20) // This avoids an unnecessary dependency to libc++abi. void operator delete(void *, size_t) {} virtual ~AbstractUnwindCursor() {} virtual bool validReg(int) { _LIBUNWIND_ABORT("validReg not implemented"); } virtual unw_word_t getReg(int) { _LIBUNWIND_ABORT("getReg not implemented"); } virtual void setReg(int, unw_word_t) { _LIBUNWIND_ABORT("setReg not implemented"); } virtual bool validFloatReg(int) { _LIBUNWIND_ABORT("validFloatReg not implemented"); } virtual unw_fpreg_t getFloatReg(int) { _LIBUNWIND_ABORT("getFloatReg not implemented"); } virtual void setFloatReg(int, unw_fpreg_t) { _LIBUNWIND_ABORT("setFloatReg not implemented"); } virtual int step() { _LIBUNWIND_ABORT("step not implemented"); } virtual void getInfo(unw_proc_info_t *) { _LIBUNWIND_ABORT("getInfo not implemented"); } virtual void jumpto() { _LIBUNWIND_ABORT("jumpto not implemented"); } virtual bool isSignalFrame() { _LIBUNWIND_ABORT("isSignalFrame not implemented"); } virtual bool getFunctionName(char *, size_t, unw_word_t *) { _LIBUNWIND_ABORT("getFunctionName not implemented"); } virtual void setInfoBasedOnIPRegister(bool = false) { _LIBUNWIND_ABORT("setInfoBasedOnIPRegister not implemented"); } virtual const char *getRegisterName(int) { _LIBUNWIND_ABORT("getRegisterName not implemented"); } #ifdef __arm__ virtual void saveVFPAsX() { _LIBUNWIND_ABORT("saveVFPAsX not implemented"); } #endif }; /// UnwindCursor contains all state (including all register values) during /// an unwind. This is normally stack allocated inside a unw_cursor_t. template class UnwindCursor : public AbstractUnwindCursor{ typedef typename A::pint_t pint_t; public: UnwindCursor(unw_context_t *context, A &as); UnwindCursor(A &as, void *threadArg); virtual ~UnwindCursor() {} virtual bool validReg(int); virtual unw_word_t getReg(int); virtual void setReg(int, unw_word_t); virtual bool validFloatReg(int); virtual unw_fpreg_t getFloatReg(int); virtual void setFloatReg(int, unw_fpreg_t); virtual int step(); virtual void getInfo(unw_proc_info_t *); virtual void jumpto(); virtual bool isSignalFrame(); virtual bool getFunctionName(char *buf, size_t len, unw_word_t *off); virtual void setInfoBasedOnIPRegister(bool isReturnAddress = false); virtual const char *getRegisterName(int num); #ifdef __arm__ virtual void saveVFPAsX(); #endif private: #if _LIBUNWIND_ARM_EHABI bool getInfoFromEHABISection(pint_t pc, const UnwindInfoSections §s); int stepWithEHABI() { size_t len = 0; size_t off = 0; // FIXME: Calling decode_eht_entry() here is violating the libunwind // abstraction layer. const uint32_t *ehtp = decode_eht_entry(reinterpret_cast(_info.unwind_info), &off, &len); if (_Unwind_VRS_Interpret((_Unwind_Context *)this, ehtp, off, len) != _URC_CONTINUE_UNWIND) return UNW_STEP_END; return UNW_STEP_SUCCESS; } #endif #if _LIBUNWIND_SUPPORT_DWARF_UNWIND bool getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections §s, uint32_t fdeSectionOffsetHint=0); int stepWithDwarfFDE() { return DwarfInstructions::stepWithDwarf(_addressSpace, (pint_t)this->getReg(UNW_REG_IP), (pint_t)_info.unwind_info, _registers); } #endif #if _LIBUNWIND_SUPPORT_COMPACT_UNWIND bool getInfoFromCompactEncodingSection(pint_t pc, const UnwindInfoSections §s); int stepWithCompactEncoding() { #if _LIBUNWIND_SUPPORT_DWARF_UNWIND if ( compactSaysUseDwarf() ) return stepWithDwarfFDE(); #endif R dummy; return stepWithCompactEncoding(dummy); } +#if defined(_LIBUNWIND_TARGET_X86_64) int stepWithCompactEncoding(Registers_x86_64 &) { return CompactUnwinder_x86_64::stepWithCompactEncoding( _info.format, _info.start_ip, _addressSpace, _registers); } +#endif +#if defined(_LIBUNWIND_TARGET_I386) int stepWithCompactEncoding(Registers_x86 &) { return CompactUnwinder_x86::stepWithCompactEncoding( _info.format, (uint32_t)_info.start_ip, _addressSpace, _registers); } +#endif +#if defined(_LIBUNWIND_TARGET_PPC) int stepWithCompactEncoding(Registers_ppc &) { return UNW_EINVAL; } +#endif +#if defined(_LIBUNWIND_TARGET_AARCH64) int stepWithCompactEncoding(Registers_arm64 &) { return CompactUnwinder_arm64::stepWithCompactEncoding( _info.format, _info.start_ip, _addressSpace, _registers); } +#endif bool compactSaysUseDwarf(uint32_t *offset=NULL) const { R dummy; return compactSaysUseDwarf(dummy, offset); } +#if defined(_LIBUNWIND_TARGET_X86_64) bool compactSaysUseDwarf(Registers_x86_64 &, uint32_t *offset) const { if ((_info.format & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF) { if (offset) *offset = (_info.format & UNWIND_X86_64_DWARF_SECTION_OFFSET); return true; } return false; } +#endif +#if defined(_LIBUNWIND_TARGET_I386) bool compactSaysUseDwarf(Registers_x86 &, uint32_t *offset) const { if ((_info.format & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF) { if (offset) *offset = (_info.format & UNWIND_X86_DWARF_SECTION_OFFSET); return true; } return false; } +#endif +#if defined(_LIBUNWIND_TARGET_PPC) bool compactSaysUseDwarf(Registers_ppc &, uint32_t *) const { return true; } +#endif +#if defined(_LIBUNWIND_TARGET_AARCH64) bool compactSaysUseDwarf(Registers_arm64 &, uint32_t *offset) const { if ((_info.format & UNWIND_ARM64_MODE_MASK) == UNWIND_ARM64_MODE_DWARF) { if (offset) *offset = (_info.format & UNWIND_ARM64_DWARF_SECTION_OFFSET); return true; } return false; } +#endif #endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND #if _LIBUNWIND_SUPPORT_DWARF_UNWIND compact_unwind_encoding_t dwarfEncoding() const { R dummy; return dwarfEncoding(dummy); } +#if defined(_LIBUNWIND_TARGET_X86_64) compact_unwind_encoding_t dwarfEncoding(Registers_x86_64 &) const { return UNWIND_X86_64_MODE_DWARF; } +#endif +#if defined(_LIBUNWIND_TARGET_I386) compact_unwind_encoding_t dwarfEncoding(Registers_x86 &) const { return UNWIND_X86_MODE_DWARF; } +#endif +#if defined(_LIBUNWIND_TARGET_PPC) compact_unwind_encoding_t dwarfEncoding(Registers_ppc &) const { return 0; } +#endif +#if defined(_LIBUNWIND_TARGET_AARCH64) compact_unwind_encoding_t dwarfEncoding(Registers_arm64 &) const { return UNWIND_ARM64_MODE_DWARF; } +#endif +#if defined (_LIBUNWIND_TARGET_OR1K) compact_unwind_encoding_t dwarfEncoding(Registers_or1k &) const { return 0; } +#endif +#if defined (_LIBUNWIND_TARGET_RISCV) compact_unwind_encoding_t dwarfEncoding(Registers_riscv &) const { return 0; } +#endif #endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND A &_addressSpace; R _registers; unw_proc_info_t _info; bool _unwindInfoMissing; bool _isSignalFrame; }; template UnwindCursor::UnwindCursor(unw_context_t *context, A &as) : _addressSpace(as), _registers(context), _unwindInfoMissing(false), _isSignalFrame(false) { - static_assert(sizeof(UnwindCursor) < sizeof(unw_cursor_t), + static_assert((check_fit, unw_cursor_t>::does_fit), "UnwindCursor<> does not fit in unw_cursor_t"); memset(&_info, 0, sizeof(_info)); } template UnwindCursor::UnwindCursor(A &as, void *) : _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false) { memset(&_info, 0, sizeof(_info)); // FIXME // fill in _registers from thread arg } template bool UnwindCursor::validReg(int regNum) { return _registers.validRegister(regNum); } template unw_word_t UnwindCursor::getReg(int regNum) { return _registers.getRegister(regNum); } template void UnwindCursor::setReg(int regNum, unw_word_t value) { _registers.setRegister(regNum, (typename A::pint_t)value); } template bool UnwindCursor::validFloatReg(int regNum) { return _registers.validFloatRegister(regNum); } template unw_fpreg_t UnwindCursor::getFloatReg(int regNum) { return _registers.getFloatRegister(regNum); } template void UnwindCursor::setFloatReg(int regNum, unw_fpreg_t value) { _registers.setFloatRegister(regNum, value); } template void UnwindCursor::jumpto() { _registers.jumpto(); } #ifdef __arm__ template void UnwindCursor::saveVFPAsX() { _registers.saveVFPAsX(); } #endif template const char *UnwindCursor::getRegisterName(int regNum) { return _registers.getRegisterName(regNum); } template bool UnwindCursor::isSignalFrame() { return _isSignalFrame; } #if _LIBUNWIND_ARM_EHABI struct EHABIIndexEntry { uint32_t functionOffset; uint32_t data; }; template struct EHABISectionIterator { typedef EHABISectionIterator _Self; typedef std::random_access_iterator_tag iterator_category; typedef typename A::pint_t value_type; typedef typename A::pint_t* pointer; typedef typename A::pint_t& reference; typedef size_t size_type; typedef size_t difference_type; static _Self begin(A& addressSpace, const UnwindInfoSections& sects) { return _Self(addressSpace, sects, 0); } static _Self end(A& addressSpace, const UnwindInfoSections& sects) { return _Self(addressSpace, sects, sects.arm_section_length); } EHABISectionIterator(A& addressSpace, const UnwindInfoSections& sects, size_t i) : _i(i), _addressSpace(&addressSpace), _sects(§s) {} _Self& operator++() { ++_i; return *this; } _Self& operator+=(size_t a) { _i += a; return *this; } _Self& operator--() { assert(_i > 0); --_i; return *this; } _Self& operator-=(size_t a) { assert(_i >= a); _i -= a; return *this; } _Self operator+(size_t a) { _Self out = *this; out._i += a; return out; } _Self operator-(size_t a) { assert(_i >= a); _Self out = *this; out._i -= a; return out; } size_t operator-(const _Self& other) { return _i - other._i; } bool operator==(const _Self& other) const { assert(_addressSpace == other._addressSpace); assert(_sects == other._sects); return _i == other._i; } typename A::pint_t operator*() const { return functionAddress(); } typename A::pint_t functionAddress() const { typename A::pint_t indexAddr = _sects->arm_section + arrayoffsetof( EHABIIndexEntry, _i, functionOffset); return indexAddr + signExtendPrel31(_addressSpace->get32(indexAddr)); } typename A::pint_t dataAddress() { typename A::pint_t indexAddr = _sects->arm_section + arrayoffsetof( EHABIIndexEntry, _i, data); return indexAddr; } private: size_t _i; A* _addressSpace; const UnwindInfoSections* _sects; }; template bool UnwindCursor::getInfoFromEHABISection( pint_t pc, const UnwindInfoSections §s) { EHABISectionIterator begin = EHABISectionIterator::begin(_addressSpace, sects); EHABISectionIterator end = EHABISectionIterator::end(_addressSpace, sects); EHABISectionIterator itNextPC = std::upper_bound(begin, end, pc); if (itNextPC == begin || itNextPC == end) return false; EHABISectionIterator itThisPC = itNextPC - 1; pint_t thisPC = itThisPC.functionAddress(); pint_t nextPC = itNextPC.functionAddress(); pint_t indexDataAddr = itThisPC.dataAddress(); if (indexDataAddr == 0) return false; uint32_t indexData = _addressSpace.get32(indexDataAddr); if (indexData == UNW_EXIDX_CANTUNWIND) return false; // If the high bit is set, the exception handling table entry is inline inside // the index table entry on the second word (aka |indexDataAddr|). Otherwise, // the table points at an offset in the exception handling table (section 5 EHABI). pint_t exceptionTableAddr; uint32_t exceptionTableData; bool isSingleWordEHT; if (indexData & 0x80000000) { exceptionTableAddr = indexDataAddr; // TODO(ajwong): Should this data be 0? exceptionTableData = indexData; isSingleWordEHT = true; } else { exceptionTableAddr = indexDataAddr + signExtendPrel31(indexData); exceptionTableData = _addressSpace.get32(exceptionTableAddr); isSingleWordEHT = false; } // Now we know the 3 things: // exceptionTableAddr -- exception handler table entry. // exceptionTableData -- the data inside the first word of the eht entry. // isSingleWordEHT -- whether the entry is in the index. unw_word_t personalityRoutine = 0xbadf00d; bool scope32 = false; uintptr_t lsda; // If the high bit in the exception handling table entry is set, the entry is // in compact form (section 6.3 EHABI). if (exceptionTableData & 0x80000000) { // Grab the index of the personality routine from the compact form. uint32_t choice = (exceptionTableData & 0x0f000000) >> 24; uint32_t extraWords = 0; switch (choice) { case 0: personalityRoutine = (unw_word_t) &__aeabi_unwind_cpp_pr0; extraWords = 0; scope32 = false; lsda = isSingleWordEHT ? 0 : (exceptionTableAddr + 4); break; case 1: personalityRoutine = (unw_word_t) &__aeabi_unwind_cpp_pr1; extraWords = (exceptionTableData & 0x00ff0000) >> 16; scope32 = false; lsda = exceptionTableAddr + (extraWords + 1) * 4; break; case 2: personalityRoutine = (unw_word_t) &__aeabi_unwind_cpp_pr2; extraWords = (exceptionTableData & 0x00ff0000) >> 16; scope32 = true; lsda = exceptionTableAddr + (extraWords + 1) * 4; break; default: _LIBUNWIND_ABORT("unknown personality routine"); return false; } if (isSingleWordEHT) { if (extraWords != 0) { _LIBUNWIND_ABORT("index inlined table detected but pr function " "requires extra words"); return false; } } } else { pint_t personalityAddr = exceptionTableAddr + signExtendPrel31(exceptionTableData); personalityRoutine = personalityAddr; // ARM EHABI # 6.2, # 9.2 // // +---- ehtp // v // +--------------------------------------+ // | +--------+--------+--------+-------+ | // | |0| prel31 to personalityRoutine | | // | +--------+--------+--------+-------+ | // | | N | unwind opcodes | | <-- UnwindData // | +--------+--------+--------+-------+ | // | | Word 2 unwind opcodes | | // | +--------+--------+--------+-------+ | // | ... | // | +--------+--------+--------+-------+ | // | | Word N unwind opcodes | | // | +--------+--------+--------+-------+ | // | | LSDA | | <-- lsda // | | ... | | // | +--------+--------+--------+-------+ | // +--------------------------------------+ uint32_t *UnwindData = reinterpret_cast(exceptionTableAddr) + 1; uint32_t FirstDataWord = *UnwindData; size_t N = ((FirstDataWord >> 24) & 0xff); size_t NDataWords = N + 1; lsda = reinterpret_cast(UnwindData + NDataWords); } _info.start_ip = thisPC; _info.end_ip = nextPC; _info.handler = personalityRoutine; _info.unwind_info = exceptionTableAddr; _info.lsda = lsda; // flags is pr_cache.additional. See EHABI #7.2 for definition of bit 0. _info.flags = isSingleWordEHT ? 1 : 0 | scope32 ? 0x2 : 0; // Use enum? return true; } #endif #if _LIBUNWIND_SUPPORT_DWARF_UNWIND template bool UnwindCursor::getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections §s, uint32_t fdeSectionOffsetHint) { typename CFI_Parser::FDE_Info fdeInfo; typename CFI_Parser::CIE_Info cieInfo; bool foundFDE = false; bool foundInCache = false; // If compact encoding table gave offset into dwarf section, go directly there if (fdeSectionOffsetHint != 0) { foundFDE = CFI_Parser::findFDE(_addressSpace, pc, sects.dwarf_section, (uint32_t)sects.dwarf_section_length, sects.dwarf_section + fdeSectionOffsetHint, &fdeInfo, &cieInfo); } #if _LIBUNWIND_SUPPORT_DWARF_INDEX if (!foundFDE && (sects.dwarf_index_section != 0)) { foundFDE = EHHeaderParser::findFDE( _addressSpace, pc, sects.dwarf_index_section, (uint32_t)sects.dwarf_index_section_length, &fdeInfo, &cieInfo); } #endif if (!foundFDE) { // otherwise, search cache of previously found FDEs. pint_t cachedFDE = DwarfFDECache::findFDE(sects.dso_base, pc); if (cachedFDE != 0) { foundFDE = CFI_Parser::findFDE(_addressSpace, pc, sects.dwarf_section, (uint32_t)sects.dwarf_section_length, cachedFDE, &fdeInfo, &cieInfo); foundInCache = foundFDE; } } if (!foundFDE) { // Still not found, do full scan of __eh_frame section. foundFDE = CFI_Parser::findFDE(_addressSpace, pc, sects.dwarf_section, (uint32_t)sects.dwarf_section_length, 0, &fdeInfo, &cieInfo); } if (foundFDE) { typename CFI_Parser::PrologInfo prolog; if (CFI_Parser::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc, &prolog)) { // Save off parsed FDE info _info.start_ip = fdeInfo.pcStart; _info.end_ip = fdeInfo.pcEnd; _info.lsda = fdeInfo.lsda; _info.handler = cieInfo.personality; _info.gp = prolog.spExtraArgSize; _info.flags = 0; _info.format = dwarfEncoding(); _info.unwind_info = fdeInfo.fdeStart; _info.unwind_info_size = (uint32_t)fdeInfo.fdeLength; _info.extra = (unw_word_t) sects.dso_base; // Add to cache (to make next lookup faster) if we had no hint // and there was no index. if (!foundInCache && (fdeSectionOffsetHint == 0)) { #if _LIBUNWIND_SUPPORT_DWARF_INDEX if (sects.dwarf_index_section == 0) #endif DwarfFDECache::add(sects.dso_base, fdeInfo.pcStart, fdeInfo.pcEnd, fdeInfo.fdeStart); } return true; } } //_LIBUNWIND_DEBUG_LOG("can't find/use FDE for pc=0x%llX\n", (uint64_t)pc); return false; } #endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND #if _LIBUNWIND_SUPPORT_COMPACT_UNWIND template bool UnwindCursor::getInfoFromCompactEncodingSection(pint_t pc, const UnwindInfoSections §s) { const bool log = false; if (log) fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX, mh=0x%llX)\n", (uint64_t)pc, (uint64_t)sects.dso_base); const UnwindSectionHeader sectionHeader(_addressSpace, sects.compact_unwind_section); if (sectionHeader.version() != UNWIND_SECTION_VERSION) return false; // do a binary search of top level index to find page with unwind info pint_t targetFunctionOffset = pc - sects.dso_base; const UnwindSectionIndexArray topIndex(_addressSpace, sects.compact_unwind_section + sectionHeader.indexSectionOffset()); uint32_t low = 0; uint32_t high = sectionHeader.indexCount(); uint32_t last = high - 1; while (low < high) { uint32_t mid = (low + high) / 2; //if ( log ) fprintf(stderr, "\tmid=%d, low=%d, high=%d, *mid=0x%08X\n", //mid, low, high, topIndex.functionOffset(mid)); if (topIndex.functionOffset(mid) <= targetFunctionOffset) { if ((mid == last) || (topIndex.functionOffset(mid + 1) > targetFunctionOffset)) { low = mid; break; } else { low = mid + 1; } } else { high = mid; } } const uint32_t firstLevelFunctionOffset = topIndex.functionOffset(low); const uint32_t firstLevelNextPageFunctionOffset = topIndex.functionOffset(low + 1); const pint_t secondLevelAddr = sects.compact_unwind_section + topIndex.secondLevelPagesSectionOffset(low); const pint_t lsdaArrayStartAddr = sects.compact_unwind_section + topIndex.lsdaIndexArraySectionOffset(low); const pint_t lsdaArrayEndAddr = sects.compact_unwind_section + topIndex.lsdaIndexArraySectionOffset(low+1); if (log) fprintf(stderr, "\tfirst level search for result index=%d " "to secondLevelAddr=0x%llX\n", low, (uint64_t) secondLevelAddr); // do a binary search of second level page index uint32_t encoding = 0; pint_t funcStart = 0; pint_t funcEnd = 0; pint_t lsda = 0; pint_t personality = 0; uint32_t pageKind = _addressSpace.get32(secondLevelAddr); if (pageKind == UNWIND_SECOND_LEVEL_REGULAR) { // regular page UnwindSectionRegularPageHeader pageHeader(_addressSpace, secondLevelAddr); UnwindSectionRegularArray pageIndex( _addressSpace, secondLevelAddr + pageHeader.entryPageOffset()); // binary search looks for entry with e where index[e].offset <= pc < // index[e+1].offset if (log) fprintf(stderr, "\tbinary search for targetFunctionOffset=0x%08llX in " "regular page starting at secondLevelAddr=0x%llX\n", (uint64_t) targetFunctionOffset, (uint64_t) secondLevelAddr); low = 0; high = pageHeader.entryCount(); while (low < high) { uint32_t mid = (low + high) / 2; if (pageIndex.functionOffset(mid) <= targetFunctionOffset) { if (mid == (uint32_t)(pageHeader.entryCount() - 1)) { // at end of table low = mid; funcEnd = firstLevelNextPageFunctionOffset + sects.dso_base; break; } else if (pageIndex.functionOffset(mid + 1) > targetFunctionOffset) { // next is too big, so we found it low = mid; funcEnd = pageIndex.functionOffset(low + 1) + sects.dso_base; break; } else { low = mid + 1; } } else { high = mid; } } encoding = pageIndex.encoding(low); funcStart = pageIndex.functionOffset(low) + sects.dso_base; if (pc < funcStart) { if (log) fprintf( stderr, "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n", (uint64_t) pc, (uint64_t) funcStart, (uint64_t) funcEnd); return false; } if (pc > funcEnd) { if (log) fprintf( stderr, "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n", (uint64_t) pc, (uint64_t) funcStart, (uint64_t) funcEnd); return false; } } else if (pageKind == UNWIND_SECOND_LEVEL_COMPRESSED) { // compressed page UnwindSectionCompressedPageHeader pageHeader(_addressSpace, secondLevelAddr); UnwindSectionCompressedArray pageIndex( _addressSpace, secondLevelAddr + pageHeader.entryPageOffset()); const uint32_t targetFunctionPageOffset = (uint32_t)(targetFunctionOffset - firstLevelFunctionOffset); // binary search looks for entry with e where index[e].offset <= pc < // index[e+1].offset if (log) fprintf(stderr, "\tbinary search of compressed page starting at " "secondLevelAddr=0x%llX\n", (uint64_t) secondLevelAddr); low = 0; last = pageHeader.entryCount() - 1; high = pageHeader.entryCount(); while (low < high) { uint32_t mid = (low + high) / 2; if (pageIndex.functionOffset(mid) <= targetFunctionPageOffset) { if ((mid == last) || (pageIndex.functionOffset(mid + 1) > targetFunctionPageOffset)) { low = mid; break; } else { low = mid + 1; } } else { high = mid; } } funcStart = pageIndex.functionOffset(low) + firstLevelFunctionOffset + sects.dso_base; if (low < last) funcEnd = pageIndex.functionOffset(low + 1) + firstLevelFunctionOffset + sects.dso_base; else funcEnd = firstLevelNextPageFunctionOffset + sects.dso_base; if (pc < funcStart) { _LIBUNWIND_DEBUG_LOG("malformed __unwind_info, pc=0x%llX not in second " "level compressed unwind table. funcStart=0x%llX\n", (uint64_t) pc, (uint64_t) funcStart); return false; } if (pc > funcEnd) { _LIBUNWIND_DEBUG_LOG("malformed __unwind_info, pc=0x%llX not in second " "level compressed unwind table. funcEnd=0x%llX\n", (uint64_t) pc, (uint64_t) funcEnd); return false; } uint16_t encodingIndex = pageIndex.encodingIndex(low); if (encodingIndex < sectionHeader.commonEncodingsArrayCount()) { // encoding is in common table in section header encoding = _addressSpace.get32( sects.compact_unwind_section + sectionHeader.commonEncodingsArraySectionOffset() + encodingIndex * sizeof(uint32_t)); } else { // encoding is in page specific table uint16_t pageEncodingIndex = encodingIndex - (uint16_t)sectionHeader.commonEncodingsArrayCount(); encoding = _addressSpace.get32(secondLevelAddr + pageHeader.encodingsPageOffset() + pageEncodingIndex * sizeof(uint32_t)); } } else { _LIBUNWIND_DEBUG_LOG("malformed __unwind_info at 0x%0llX bad second " "level page\n", (uint64_t) sects.compact_unwind_section); return false; } // look up LSDA, if encoding says function has one if (encoding & UNWIND_HAS_LSDA) { UnwindSectionLsdaArray lsdaIndex(_addressSpace, lsdaArrayStartAddr); uint32_t funcStartOffset = (uint32_t)(funcStart - sects.dso_base); low = 0; high = (uint32_t)(lsdaArrayEndAddr - lsdaArrayStartAddr) / sizeof(unwind_info_section_header_lsda_index_entry); // binary search looks for entry with exact match for functionOffset if (log) fprintf(stderr, "\tbinary search of lsda table for targetFunctionOffset=0x%08X\n", funcStartOffset); while (low < high) { uint32_t mid = (low + high) / 2; if (lsdaIndex.functionOffset(mid) == funcStartOffset) { lsda = lsdaIndex.lsdaOffset(mid) + sects.dso_base; break; } else if (lsdaIndex.functionOffset(mid) < funcStartOffset) { low = mid + 1; } else { high = mid; } } if (lsda == 0) { _LIBUNWIND_DEBUG_LOG("found encoding 0x%08X with HAS_LSDA bit set for " "pc=0x%0llX, but lsda table has no entry\n", encoding, (uint64_t) pc); return false; } } // extact personality routine, if encoding says function has one uint32_t personalityIndex = (encoding & UNWIND_PERSONALITY_MASK) >> (__builtin_ctz(UNWIND_PERSONALITY_MASK)); if (personalityIndex != 0) { --personalityIndex; // change 1-based to zero-based index if (personalityIndex > sectionHeader.personalityArrayCount()) { _LIBUNWIND_DEBUG_LOG("found encoding 0x%08X with personality index %d, " "but personality table has only %d entires\n", encoding, personalityIndex, sectionHeader.personalityArrayCount()); return false; } int32_t personalityDelta = (int32_t)_addressSpace.get32( sects.compact_unwind_section + sectionHeader.personalityArraySectionOffset() + personalityIndex * sizeof(uint32_t)); pint_t personalityPointer = sects.dso_base + (pint_t)personalityDelta; personality = _addressSpace.getP(personalityPointer); if (log) fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), " "personalityDelta=0x%08X, personality=0x%08llX\n", (uint64_t) pc, personalityDelta, (uint64_t) personality); } if (log) fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), " "encoding=0x%08X, lsda=0x%08llX for funcStart=0x%llX\n", (uint64_t) pc, encoding, (uint64_t) lsda, (uint64_t) funcStart); _info.start_ip = funcStart; _info.end_ip = funcEnd; _info.lsda = lsda; _info.handler = personality; _info.gp = 0; _info.flags = 0; _info.format = encoding; _info.unwind_info = 0; _info.unwind_info_size = 0; _info.extra = sects.dso_base; return true; } #endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND template void UnwindCursor::setInfoBasedOnIPRegister(bool isReturnAddress) { pint_t pc = (pint_t)this->getReg(UNW_REG_IP); #if _LIBUNWIND_ARM_EHABI // Remove the thumb bit so the IP represents the actual instruction address. // This matches the behaviour of _Unwind_GetIP on arm. pc &= (pint_t)~0x1; #endif // If the last line of a function is a "throw" the compiler sometimes // emits no instructions after the call to __cxa_throw. This means // the return address is actually the start of the next function. // To disambiguate this, back up the pc when we know it is a return // address. if (isReturnAddress) --pc; // Ask address space object to find unwind sections for this pc. UnwindInfoSections sects; if (_addressSpace.findUnwindSections(pc, sects)) { #if _LIBUNWIND_SUPPORT_COMPACT_UNWIND // If there is a compact unwind encoding table, look there first. if (sects.compact_unwind_section != 0) { if (this->getInfoFromCompactEncodingSection(pc, sects)) { #if _LIBUNWIND_SUPPORT_DWARF_UNWIND // Found info in table, done unless encoding says to use dwarf. uint32_t dwarfOffset; if ((sects.dwarf_section != 0) && compactSaysUseDwarf(&dwarfOffset)) { if (this->getInfoFromDwarfSection(pc, sects, dwarfOffset)) { // found info in dwarf, done return; } } #endif // If unwind table has entry, but entry says there is no unwind info, // record that we have no unwind info. if (_info.format == 0) _unwindInfoMissing = true; return; } } #endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND #if _LIBUNWIND_SUPPORT_DWARF_UNWIND // If there is dwarf unwind info, look there next. if (sects.dwarf_section != 0) { if (this->getInfoFromDwarfSection(pc, sects)) { // found info in dwarf, done return; } } #endif #if _LIBUNWIND_ARM_EHABI // If there is ARM EHABI unwind info, look there next. if (sects.arm_section != 0 && this->getInfoFromEHABISection(pc, sects)) return; #endif } #if _LIBUNWIND_SUPPORT_DWARF_UNWIND // There is no static unwind info for this pc. Look to see if an FDE was // dynamically registered for it. pint_t cachedFDE = DwarfFDECache::findFDE(0, pc); if (cachedFDE != 0) { CFI_Parser::FDE_Info fdeInfo; CFI_Parser::CIE_Info cieInfo; const char *msg = CFI_Parser::decodeFDE(_addressSpace, cachedFDE, &fdeInfo, &cieInfo); if (msg == NULL) { typename CFI_Parser::PrologInfo prolog; if (CFI_Parser::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc, &prolog)) { // save off parsed FDE info _info.start_ip = fdeInfo.pcStart; _info.end_ip = fdeInfo.pcEnd; _info.lsda = fdeInfo.lsda; _info.handler = cieInfo.personality; _info.gp = prolog.spExtraArgSize; // Some frameless functions need SP // altered when resuming in function. _info.flags = 0; _info.format = dwarfEncoding(); _info.unwind_info = fdeInfo.fdeStart; _info.unwind_info_size = (uint32_t)fdeInfo.fdeLength; _info.extra = 0; return; } } } // Lastly, ask AddressSpace object about platform specific ways to locate // other FDEs. pint_t fde; if (_addressSpace.findOtherFDE(pc, fde)) { CFI_Parser::FDE_Info fdeInfo; CFI_Parser::CIE_Info cieInfo; if (!CFI_Parser::decodeFDE(_addressSpace, fde, &fdeInfo, &cieInfo)) { // Double check this FDE is for a function that includes the pc. if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd)) { typename CFI_Parser::PrologInfo prolog; if (CFI_Parser::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc, &prolog)) { // save off parsed FDE info _info.start_ip = fdeInfo.pcStart; _info.end_ip = fdeInfo.pcEnd; _info.lsda = fdeInfo.lsda; _info.handler = cieInfo.personality; _info.gp = prolog.spExtraArgSize; _info.flags = 0; _info.format = dwarfEncoding(); _info.unwind_info = fdeInfo.fdeStart; _info.unwind_info_size = (uint32_t)fdeInfo.fdeLength; _info.extra = 0; return; } } } } #endif // #if _LIBUNWIND_SUPPORT_DWARF_UNWIND // no unwind info, flag that we can't reliably unwind _unwindInfoMissing = true; } template int UnwindCursor::step() { // Bottom of stack is defined is when unwind info cannot be found. if (_unwindInfoMissing) return UNW_STEP_END; // Use unwinding info to modify register set as if function returned. int result; #if _LIBUNWIND_SUPPORT_COMPACT_UNWIND result = this->stepWithCompactEncoding(); #elif _LIBUNWIND_SUPPORT_DWARF_UNWIND result = this->stepWithDwarfFDE(); #elif _LIBUNWIND_ARM_EHABI result = this->stepWithEHABI(); #else #error Need _LIBUNWIND_SUPPORT_COMPACT_UNWIND or \ _LIBUNWIND_SUPPORT_DWARF_UNWIND or \ _LIBUNWIND_ARM_EHABI #endif // update info based on new PC if (result == UNW_STEP_SUCCESS) { this->setInfoBasedOnIPRegister(true); if (_unwindInfoMissing) return UNW_STEP_END; if (_info.gp) setReg(UNW_REG_SP, getReg(UNW_REG_SP) + _info.gp); } return result; } template void UnwindCursor::getInfo(unw_proc_info_t *info) { *info = _info; } template bool UnwindCursor::getFunctionName(char *buf, size_t bufLen, unw_word_t *offset) { return _addressSpace.findFunctionName((pint_t)this->getReg(UNW_REG_IP), buf, bufLen, offset); } } // namespace libunwind #endif // __UNWINDCURSOR_HPP__ Index: head/contrib/llvm/projects/libunwind/src/UnwindLevel1.c =================================================================== --- head/contrib/llvm/projects/libunwind/src/UnwindLevel1.c (revision 302449) +++ head/contrib/llvm/projects/libunwind/src/UnwindLevel1.c (revision 302450) @@ -1,506 +1,506 @@ //===------------------------- UnwindLevel1.c -----------------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // // // Implements C++ ABI Exception Handling Level 1 as documented at: // http://mentorembedded.github.io/cxx-abi/abi-eh.html // using libunwind // //===----------------------------------------------------------------------===// // ARM EHABI does not specify _Unwind_{Get,Set}{GR,IP}(). Thus, we are // defining inline functions to delegate the function calls to // _Unwind_VRS_{Get,Set}(). However, some applications might declare the // function protetype directly (instead of including ), thus we need // to export these functions from libunwind.so as well. #define _LIBUNWIND_UNWIND_LEVEL1_EXTERNAL_LINKAGE 1 #include #include #include #include #include #include #include "libunwind.h" #include "unwind.h" #include "config.h" #if !_LIBUNWIND_ARM_EHABI static _Unwind_Reason_Code -unwind_phase1(unw_context_t *uc, _Unwind_Exception *exception_object) { - unw_cursor_t cursor1; - unw_init_local(&cursor1, uc); +unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) { + unw_init_local(cursor, uc); // Walk each frame looking for a place to stop. bool handlerNotFound = true; while (handlerNotFound) { // Ask libuwind to get next frame (skip over first which is // _Unwind_RaiseException). - int stepResult = unw_step(&cursor1); + int stepResult = unw_step(cursor); if (stepResult == 0) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step() reached " "bottom => _URC_END_OF_STACK\n", (void *)exception_object); return _URC_END_OF_STACK; } else if (stepResult < 0) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step failed => " "_URC_FATAL_PHASE1_ERROR\n", (void *)exception_object); return _URC_FATAL_PHASE1_ERROR; } // See if frame has code to run (has personality routine). unw_proc_info_t frameInfo; unw_word_t sp; - if (unw_get_proc_info(&cursor1, &frameInfo) != UNW_ESUCCESS) { + if (unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_get_proc_info " "failed => _URC_FATAL_PHASE1_ERROR\n", (void *)exception_object); return _URC_FATAL_PHASE1_ERROR; } // When tracing, print state information. if (_LIBUNWIND_TRACING_UNWINDING) { char functionBuf[512]; const char *functionName = functionBuf; unw_word_t offset; - if ((unw_get_proc_name(&cursor1, functionBuf, sizeof(functionBuf), + if ((unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), &offset) != UNW_ESUCCESS) || (frameInfo.start_ip + offset > frameInfo.end_ip)) functionName = ".anonymous."; unw_word_t pc; - unw_get_reg(&cursor1, UNW_REG_IP, &pc); + unw_get_reg(cursor, UNW_REG_IP, &pc); _LIBUNWIND_TRACE_UNWINDING( "unwind_phase1(ex_ojb=%p): pc=0x%" PRIx64 ", start_ip=0x%" PRIx64 ", func=%s, lsda=0x%" PRIx64 ", personality=0x%" PRIx64 "\n", (void *)exception_object, pc, frameInfo.start_ip, functionName, frameInfo.lsda, frameInfo.handler); } // If there is a personality routine, ask it if it will want to stop at // this frame. if (frameInfo.handler != 0) { __personality_routine p = (__personality_routine)(long)(frameInfo.handler); _LIBUNWIND_TRACE_UNWINDING( "unwind_phase1(ex_ojb=%p): calling personality function %p\n", (void *)exception_object, (void *)(uintptr_t)p); _Unwind_Reason_Code personalityResult = (*p)(1, _UA_SEARCH_PHASE, exception_object->exception_class, - exception_object, (struct _Unwind_Context *)(&cursor1)); + exception_object, (struct _Unwind_Context *)(cursor)); switch (personalityResult) { case _URC_HANDLER_FOUND: // found a catch clause or locals that need destructing in this frame // stop search and remember stack pointer at the frame handlerNotFound = false; - unw_get_reg(&cursor1, UNW_REG_SP, &sp); + unw_get_reg(cursor, UNW_REG_SP, &sp); exception_object->private_2 = (uintptr_t)sp; _LIBUNWIND_TRACE_UNWINDING( "unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND \n", (void *)exception_object); return _URC_NO_REASON; case _URC_CONTINUE_UNWIND: _LIBUNWIND_TRACE_UNWINDING( "unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", (void *)exception_object); // continue unwinding break; default: // something went wrong _LIBUNWIND_TRACE_UNWINDING( "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n", (void *)exception_object); return _URC_FATAL_PHASE1_ERROR; } } } return _URC_NO_REASON; } static _Unwind_Reason_Code -unwind_phase2(unw_context_t *uc, _Unwind_Exception *exception_object) { - unw_cursor_t cursor2; - unw_init_local(&cursor2, uc); +unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) { + unw_init_local(cursor, uc); _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)\n", (void *)exception_object); // Walk each frame until we reach where search phase said to stop. while (true) { // Ask libuwind to get next frame (skip over first which is // _Unwind_RaiseException). - int stepResult = unw_step(&cursor2); + int stepResult = unw_step(cursor); if (stepResult == 0) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached " "bottom => _URC_END_OF_STACK\n", (void *)exception_object); return _URC_END_OF_STACK; } else if (stepResult < 0) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step failed => " "_URC_FATAL_PHASE1_ERROR\n", (void *)exception_object); return _URC_FATAL_PHASE2_ERROR; } // Get info about this frame. unw_word_t sp; unw_proc_info_t frameInfo; - unw_get_reg(&cursor2, UNW_REG_SP, &sp); - if (unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) { + unw_get_reg(cursor, UNW_REG_SP, &sp); + if (unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_get_proc_info " "failed => _URC_FATAL_PHASE1_ERROR\n", (void *)exception_object); return _URC_FATAL_PHASE2_ERROR; } // When tracing, print state information. if (_LIBUNWIND_TRACING_UNWINDING) { char functionBuf[512]; const char *functionName = functionBuf; unw_word_t offset; - if ((unw_get_proc_name(&cursor2, functionBuf, sizeof(functionBuf), + if ((unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), &offset) != UNW_ESUCCESS) || (frameInfo.start_ip + offset > frameInfo.end_ip)) functionName = ".anonymous."; _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIx64 ", func=%s, sp=0x%" PRIx64 ", lsda=0x%" PRIx64 ", personality=0x%" PRIx64 "\n", (void *)exception_object, frameInfo.start_ip, functionName, sp, frameInfo.lsda, frameInfo.handler); } // If there is a personality routine, tell it we are unwinding. if (frameInfo.handler != 0) { __personality_routine p = (__personality_routine)(long)(frameInfo.handler); _Unwind_Action action = _UA_CLEANUP_PHASE; if (sp == exception_object->private_2) { // Tell personality this was the frame it marked in phase 1. action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME); } _Unwind_Reason_Code personalityResult = (*p)(1, action, exception_object->exception_class, exception_object, - (struct _Unwind_Context *)(&cursor2)); + (struct _Unwind_Context *)(cursor)); switch (personalityResult) { case _URC_CONTINUE_UNWIND: // Continue unwinding _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", (void *)exception_object); if (sp == exception_object->private_2) { // Phase 1 said we would stop at this frame, but we did not... _LIBUNWIND_ABORT("during phase1 personality function said it would " "stop here, but now in phase2 it did not stop here"); } break; case _URC_INSTALL_CONTEXT: _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT\n", (void *)exception_object); // Personality routine says to transfer control to landing pad. // We may get control back if landing pad calls _Unwind_Resume(). if (_LIBUNWIND_TRACING_UNWINDING) { unw_word_t pc; - unw_get_reg(&cursor2, UNW_REG_IP, &pc); - unw_get_reg(&cursor2, UNW_REG_SP, &sp); + unw_get_reg(cursor, UNW_REG_IP, &pc); + unw_get_reg(cursor, UNW_REG_SP, &sp); _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering " "user code with ip=0x%" PRIx64 ", sp=0x%" PRIx64 "\n", (void *)exception_object, pc, sp); } - unw_resume(&cursor2); + unw_resume(cursor); // unw_resume() only returns if there was an error. return _URC_FATAL_PHASE2_ERROR; default: // Personality routine returned an unknown result code. _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d", personalityResult); return _URC_FATAL_PHASE2_ERROR; } } } // Clean up phase did not resume at the frame that the search phase // said it would... return _URC_FATAL_PHASE2_ERROR; } static _Unwind_Reason_Code -unwind_phase2_forced(unw_context_t *uc, +unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object, _Unwind_Stop_Fn stop, void *stop_parameter) { - unw_cursor_t cursor2; - unw_init_local(&cursor2, uc); + unw_init_local(cursor, uc); // Walk each frame until we reach where search phase said to stop - while (unw_step(&cursor2) > 0) { + while (unw_step(cursor) > 0) { // Update info about this frame. unw_proc_info_t frameInfo; - if (unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) { + if (unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): unw_step " "failed => _URC_END_OF_STACK\n", (void *)exception_object); return _URC_FATAL_PHASE2_ERROR; } // When tracing, print state information. if (_LIBUNWIND_TRACING_UNWINDING) { char functionBuf[512]; const char *functionName = functionBuf; unw_word_t offset; - if ((unw_get_proc_name(&cursor2, functionBuf, sizeof(functionBuf), + if ((unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), &offset) != UNW_ESUCCESS) || (frameInfo.start_ip + offset > frameInfo.end_ip)) functionName = ".anonymous."; _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIx64 ", func=%s, lsda=0x%" PRIx64 ", personality=0x%" PRIx64 "\n", (void *)exception_object, frameInfo.start_ip, functionName, frameInfo.lsda, frameInfo.handler); } // Call stop function at each frame. _Unwind_Action action = (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE); _Unwind_Reason_Code stopResult = (*stop)(1, action, exception_object->exception_class, exception_object, - (struct _Unwind_Context *)(&cursor2), stop_parameter); + (struct _Unwind_Context *)(cursor), stop_parameter); _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2_forced(ex_ojb=%p): stop function returned %d\n", (void *)exception_object, stopResult); if (stopResult != _URC_NO_REASON) { _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2_forced(ex_ojb=%p): stopped by stop function\n", (void *)exception_object); return _URC_FATAL_PHASE2_ERROR; } // If there is a personality routine, tell it we are unwinding. if (frameInfo.handler != 0) { __personality_routine p = (__personality_routine)(long)(frameInfo.handler); _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2_forced(ex_ojb=%p): calling personality function %p\n", (void *)exception_object, (void *)(uintptr_t)p); _Unwind_Reason_Code personalityResult = (*p)(1, action, exception_object->exception_class, exception_object, - (struct _Unwind_Context *)(&cursor2)); + (struct _Unwind_Context *)(cursor)); switch (personalityResult) { case _URC_CONTINUE_UNWIND: _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " "personality returned " "_URC_CONTINUE_UNWIND\n", (void *)exception_object); // Destructors called, continue unwinding break; case _URC_INSTALL_CONTEXT: _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " "personality returned " "_URC_INSTALL_CONTEXT\n", (void *)exception_object); // We may get control back if landing pad calls _Unwind_Resume(). - unw_resume(&cursor2); + unw_resume(cursor); break; default: // Personality routine returned an unknown result code. _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " "personality returned %d, " "_URC_FATAL_PHASE2_ERROR\n", (void *)exception_object, personalityResult); return _URC_FATAL_PHASE2_ERROR; } } } // Call stop function one last time and tell it we've reached the end // of the stack. _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop " "function with _UA_END_OF_STACK\n", (void *)exception_object); _Unwind_Action lastAction = (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK); (*stop)(1, lastAction, exception_object->exception_class, exception_object, - (struct _Unwind_Context *)(&cursor2), stop_parameter); + (struct _Unwind_Context *)(cursor), stop_parameter); // Clean up phase did not resume at the frame that the search phase said it // would. return _URC_FATAL_PHASE2_ERROR; } /// Called by __cxa_throw. Only returns if there is a fatal error. _LIBUNWIND_EXPORT _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception *exception_object) { _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)\n", (void *)exception_object); unw_context_t uc; + unw_cursor_t cursor; unw_getcontext(&uc); // Mark that this is a non-forced unwind, so _Unwind_Resume() // can do the right thing. exception_object->private_1 = 0; exception_object->private_2 = 0; // phase 1: the search phase - _Unwind_Reason_Code phase1 = unwind_phase1(&uc, exception_object); + _Unwind_Reason_Code phase1 = unwind_phase1(&uc, &cursor, exception_object); if (phase1 != _URC_NO_REASON) return phase1; // phase 2: the clean up phase - return unwind_phase2(&uc, exception_object); + return unwind_phase2(&uc, &cursor, exception_object); } /// When _Unwind_RaiseException() is in phase2, it hands control /// to the personality function at each frame. The personality /// may force a jump to a landing pad in that function, the landing /// pad code may then call _Unwind_Resume() to continue with the /// unwinding. Note: the call to _Unwind_Resume() is from compiler /// geneated user code. All other _Unwind_* routines are called /// by the C++ runtime __cxa_* routines. /// /// Note: re-throwing an exception (as opposed to continuing the unwind) /// is implemented by having the code call __cxa_rethrow() which /// in turn calls _Unwind_Resume_or_Rethrow(). _LIBUNWIND_EXPORT void _Unwind_Resume(_Unwind_Exception *exception_object) { _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)\n", (void *)exception_object); unw_context_t uc; + unw_cursor_t cursor; unw_getcontext(&uc); if (exception_object->private_1 != 0) - unwind_phase2_forced(&uc, exception_object, + unwind_phase2_forced(&uc, &cursor, exception_object, (_Unwind_Stop_Fn) exception_object->private_1, (void *)exception_object->private_2); else - unwind_phase2(&uc, exception_object); + unwind_phase2(&uc, &cursor, exception_object); // Clients assume _Unwind_Resume() does not return, so all we can do is abort. _LIBUNWIND_ABORT("_Unwind_Resume() can't return"); } /// Not used by C++. /// Unwinds stack, calling "stop" function at each frame. /// Could be used to implement longjmp(). _LIBUNWIND_EXPORT _Unwind_Reason_Code _Unwind_ForcedUnwind(_Unwind_Exception *exception_object, _Unwind_Stop_Fn stop, void *stop_parameter) { _LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)\n", (void *)exception_object, (void *)(uintptr_t)stop); unw_context_t uc; + unw_cursor_t cursor; unw_getcontext(&uc); // Mark that this is a forced unwind, so _Unwind_Resume() can do // the right thing. exception_object->private_1 = (uintptr_t) stop; exception_object->private_2 = (uintptr_t) stop_parameter; // do it - return unwind_phase2_forced(&uc, exception_object, stop, stop_parameter); + return unwind_phase2_forced(&uc, &cursor, exception_object, stop, stop_parameter); } /// Called by personality handler during phase 2 to get LSDA for current frame. _LIBUNWIND_EXPORT uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { unw_cursor_t *cursor = (unw_cursor_t *)context; unw_proc_info_t frameInfo; uintptr_t result = 0; if (unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) result = (uintptr_t)frameInfo.lsda; _LIBUNWIND_TRACE_API( "_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR "\n", (void *)context, result); if (result != 0) { if (*((uint8_t *)result) != 0xFF) _LIBUNWIND_DEBUG_LOG("lsda at 0x%" PRIxPTR " does not start with 0xFF\n", result); } return result; } /// Called by personality handler during phase 2 to find the start of the /// function. _LIBUNWIND_EXPORT uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context *context) { unw_cursor_t *cursor = (unw_cursor_t *)context; unw_proc_info_t frameInfo; uintptr_t result = 0; if (unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) result = (uintptr_t)frameInfo.start_ip; _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%" PRIxPTR "\n", (void *)context, result); return result; } /// Called by personality handler during phase 2 if a foreign exception // is caught. _LIBUNWIND_EXPORT void _Unwind_DeleteException(_Unwind_Exception *exception_object) { _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)\n", (void *)exception_object); if (exception_object->exception_cleanup != NULL) (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, exception_object); } /// Called by personality handler during phase 2 to get register values. _LIBUNWIND_EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index) { unw_cursor_t *cursor = (unw_cursor_t *)context; unw_word_t result; unw_get_reg(cursor, index, &result); _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%" PRIx64 "\n", (void *)context, index, (uint64_t)result); return (uintptr_t)result; } /// Called by personality handler during phase 2 to alter register values. _LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index, uintptr_t value) { _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0" PRIx64 ")\n", (void *)context, index, (uint64_t)value); unw_cursor_t *cursor = (unw_cursor_t *)context; unw_set_reg(cursor, index, value); } /// Called by personality handler during phase 2 to get instruction pointer. _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) { unw_cursor_t *cursor = (unw_cursor_t *)context; unw_word_t result; unw_get_reg(cursor, UNW_REG_IP, &result); _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIx64 "\n", (void *)context, (uint64_t)result); return (uintptr_t)result; } /// Called by personality handler during phase 2 to alter instruction pointer, /// such as setting where the landing pad is, so _Unwind_Resume() will /// start executing in the landing pad. _LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context, uintptr_t value) { _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0" PRIx64 ")\n", (void *)context, (uint64_t)value); unw_cursor_t *cursor = (unw_cursor_t *)context; unw_set_reg(cursor, UNW_REG_IP, value); } #endif // !_LIBUNWIND_ARM_EHABI Index: head/contrib/llvm/projects/libunwind/src/UnwindRegistersRestore.S =================================================================== --- head/contrib/llvm/projects/libunwind/src/UnwindRegistersRestore.S (revision 302449) +++ head/contrib/llvm/projects/libunwind/src/UnwindRegistersRestore.S (revision 302450) @@ -1,485 +1,485 @@ //===-------------------- UnwindRegistersRestore.S ------------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "assembly.h" .text #if defined(__i386__) DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_x866jumptoEv) # # void libunwind::Registers_x86::jumpto() # # On entry: # + + # +-----------------------+ # + thread_state pointer + # +-----------------------+ # + return address + # +-----------------------+ <-- SP # + + movl 4(%esp), %eax # set up eax and ret on new stack location movl 28(%eax), %edx # edx holds new stack pointer subl $8,%edx movl %edx, 28(%eax) movl 0(%eax), %ebx movl %ebx, 0(%edx) movl 40(%eax), %ebx movl %ebx, 4(%edx) # we now have ret and eax pushed onto where new stack will be # restore all registers movl 4(%eax), %ebx movl 8(%eax), %ecx movl 12(%eax), %edx movl 16(%eax), %edi movl 20(%eax), %esi movl 24(%eax), %ebp movl 28(%eax), %esp # skip ss # skip eflags pop %eax # eax was already pushed on new stack ret # eip was already pushed on new stack # skip cs # skip ds # skip es # skip fs # skip gs #elif defined(__x86_64__) DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind16Registers_x86_646jumptoEv) # # void libunwind::Registers_x86_64::jumpto() # # On entry, thread_state pointer is in rdi movq 56(%rdi), %rax # rax holds new stack pointer subq $16, %rax movq %rax, 56(%rdi) movq 32(%rdi), %rbx # store new rdi on new stack movq %rbx, 0(%rax) movq 128(%rdi), %rbx # store new rip on new stack movq %rbx, 8(%rax) # restore all registers movq 0(%rdi), %rax movq 8(%rdi), %rbx movq 16(%rdi), %rcx movq 24(%rdi), %rdx # restore rdi later movq 40(%rdi), %rsi movq 48(%rdi), %rbp # restore rsp later movq 64(%rdi), %r8 movq 72(%rdi), %r9 movq 80(%rdi), %r10 movq 88(%rdi), %r11 movq 96(%rdi), %r12 movq 104(%rdi), %r13 movq 112(%rdi), %r14 movq 120(%rdi), %r15 # skip rflags # skip cs # skip fs # skip gs movq 56(%rdi), %rsp # cut back rsp to new location pop %rdi # rdi was saved here earlier ret # rip was saved here #elif defined(__ppc__) DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv) ; ; void libunwind::Registers_ppc::jumpto() ; ; On entry: ; thread_state pointer is in r3 ; ; restore integral registerrs ; skip r0 for now ; skip r1 for now lwz r2, 16(r3) ; skip r3 for now ; skip r4 for now ; skip r5 for now lwz r6, 32(r3) lwz r7, 36(r3) lwz r8, 40(r3) lwz r9, 44(r3) lwz r10, 48(r3) lwz r11, 52(r3) lwz r12, 56(r3) lwz r13, 60(r3) lwz r14, 64(r3) lwz r15, 68(r3) lwz r16, 72(r3) lwz r17, 76(r3) lwz r18, 80(r3) lwz r19, 84(r3) lwz r20, 88(r3) lwz r21, 92(r3) lwz r22, 96(r3) lwz r23,100(r3) lwz r24,104(r3) lwz r25,108(r3) lwz r26,112(r3) lwz r27,116(r3) lwz r28,120(r3) lwz r29,124(r3) lwz r30,128(r3) lwz r31,132(r3) ; restore float registers lfd f0, 160(r3) lfd f1, 168(r3) lfd f2, 176(r3) lfd f3, 184(r3) lfd f4, 192(r3) lfd f5, 200(r3) lfd f6, 208(r3) lfd f7, 216(r3) lfd f8, 224(r3) lfd f9, 232(r3) lfd f10,240(r3) lfd f11,248(r3) lfd f12,256(r3) lfd f13,264(r3) lfd f14,272(r3) lfd f15,280(r3) lfd f16,288(r3) lfd f17,296(r3) lfd f18,304(r3) lfd f19,312(r3) lfd f20,320(r3) lfd f21,328(r3) lfd f22,336(r3) lfd f23,344(r3) lfd f24,352(r3) lfd f25,360(r3) lfd f26,368(r3) lfd f27,376(r3) lfd f28,384(r3) lfd f29,392(r3) lfd f30,400(r3) lfd f31,408(r3) ; restore vector registers if any are in use lwz r5,156(r3) ; test VRsave cmpwi r5,0 beq Lnovec subi r4,r1,16 rlwinm r4,r4,0,0,27 ; mask low 4-bits ; r4 is now a 16-byte aligned pointer into the red zone ; the _vectorRegisters may not be 16-byte aligned so copy via red zone temp buffer #define LOAD_VECTOR_UNALIGNEDl(_index) \ andis. r0,r5,(1<<(15-_index)) @\ beq Ldone ## _index @\ lwz r0, 424+_index*16(r3) @\ stw r0, 0(r4) @\ lwz r0, 424+_index*16+4(r3) @\ stw r0, 4(r4) @\ lwz r0, 424+_index*16+8(r3) @\ stw r0, 8(r4) @\ lwz r0, 424+_index*16+12(r3)@\ stw r0, 12(r4) @\ lvx v ## _index,0,r4 @\ Ldone ## _index: #define LOAD_VECTOR_UNALIGNEDh(_index) \ andi. r0,r5,(1<<(31-_index)) @\ beq Ldone ## _index @\ lwz r0, 424+_index*16(r3) @\ stw r0, 0(r4) @\ lwz r0, 424+_index*16+4(r3) @\ stw r0, 4(r4) @\ lwz r0, 424+_index*16+8(r3) @\ stw r0, 8(r4) @\ lwz r0, 424+_index*16+12(r3)@\ stw r0, 12(r4) @\ lvx v ## _index,0,r4 @\ Ldone ## _index: LOAD_VECTOR_UNALIGNEDl(0) LOAD_VECTOR_UNALIGNEDl(1) LOAD_VECTOR_UNALIGNEDl(2) LOAD_VECTOR_UNALIGNEDl(3) LOAD_VECTOR_UNALIGNEDl(4) LOAD_VECTOR_UNALIGNEDl(5) LOAD_VECTOR_UNALIGNEDl(6) LOAD_VECTOR_UNALIGNEDl(7) LOAD_VECTOR_UNALIGNEDl(8) LOAD_VECTOR_UNALIGNEDl(9) LOAD_VECTOR_UNALIGNEDl(10) LOAD_VECTOR_UNALIGNEDl(11) LOAD_VECTOR_UNALIGNEDl(12) LOAD_VECTOR_UNALIGNEDl(13) LOAD_VECTOR_UNALIGNEDl(14) LOAD_VECTOR_UNALIGNEDl(15) LOAD_VECTOR_UNALIGNEDh(16) LOAD_VECTOR_UNALIGNEDh(17) LOAD_VECTOR_UNALIGNEDh(18) LOAD_VECTOR_UNALIGNEDh(19) LOAD_VECTOR_UNALIGNEDh(20) LOAD_VECTOR_UNALIGNEDh(21) LOAD_VECTOR_UNALIGNEDh(22) LOAD_VECTOR_UNALIGNEDh(23) LOAD_VECTOR_UNALIGNEDh(24) LOAD_VECTOR_UNALIGNEDh(25) LOAD_VECTOR_UNALIGNEDh(26) LOAD_VECTOR_UNALIGNEDh(27) LOAD_VECTOR_UNALIGNEDh(28) LOAD_VECTOR_UNALIGNEDh(29) LOAD_VECTOR_UNALIGNEDh(30) LOAD_VECTOR_UNALIGNEDh(31) Lnovec: lwz r0, 136(r3) ; __cr mtocrf 255,r0 lwz r0, 148(r3) ; __ctr mtctr r0 lwz r0, 0(r3) ; __ssr0 mtctr r0 lwz r0, 8(r3) ; do r0 now lwz r5,28(r3) ; do r5 now lwz r4,24(r3) ; do r4 now lwz r1,12(r3) ; do sp now lwz r3,20(r3) ; do r3 last bctr #elif defined(__arm64__) || defined(__aarch64__) // // void libunwind::Registers_arm64::jumpto() // // On entry: // thread_state pointer is in x0 // .p2align 2 DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind15Registers_arm646jumptoEv) // skip restore of x0,x1 for now ldp x2, x3, [x0, #0x010] ldp x4, x5, [x0, #0x020] ldp x6, x7, [x0, #0x030] ldp x8, x9, [x0, #0x040] ldp x10,x11, [x0, #0x050] ldp x12,x13, [x0, #0x060] ldp x14,x15, [x0, #0x070] ldp x16,x17, [x0, #0x080] ldp x18,x19, [x0, #0x090] ldp x20,x21, [x0, #0x0A0] ldp x22,x23, [x0, #0x0B0] ldp x24,x25, [x0, #0x0C0] ldp x26,x27, [x0, #0x0D0] - ldp x28,fp, [x0, #0x0E0] - ldr lr, [x0, #0x100] // restore pc into lr + ldp x28,x29, [x0, #0x0E0] + ldr x30, [x0, #0x100] // restore pc into lr ldr x1, [x0, #0x0F8] mov sp,x1 // restore sp ldp d0, d1, [x0, #0x110] ldp d2, d3, [x0, #0x120] ldp d4, d5, [x0, #0x130] ldp d6, d7, [x0, #0x140] ldp d8, d9, [x0, #0x150] ldp d10,d11, [x0, #0x160] ldp d12,d13, [x0, #0x170] ldp d14,d15, [x0, #0x180] ldp d16,d17, [x0, #0x190] ldp d18,d19, [x0, #0x1A0] ldp d20,d21, [x0, #0x1B0] ldp d22,d23, [x0, #0x1C0] ldp d24,d25, [x0, #0x1D0] ldp d26,d27, [x0, #0x1E0] ldp d28,d29, [x0, #0x1F0] ldr d30, [x0, #0x200] ldr d31, [x0, #0x208] ldp x0, x1, [x0, #0x000] // restore x0,x1 - ret lr // jump to pc + ret x30 // jump to pc #elif defined(__arm__) && !defined(__APPLE__) #if !defined(__ARM_ARCH_ISA_ARM) .thumb #endif @ @ void libunwind::Registers_arm::restoreCoreAndJumpTo() @ @ On entry: @ thread_state pointer is in r0 @ .p2align 2 DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm20restoreCoreAndJumpToEv) #if !defined(__ARM_ARCH_ISA_ARM) ldr r2, [r0, #52] ldr r3, [r0, #60] mov sp, r2 mov lr, r3 @ restore pc into lr ldm r0, {r0-r7} #else @ Use lr as base so that r0 can be restored. mov lr, r0 @ 32bit thumb-2 restrictions for ldm: @ . the sp (r13) cannot be in the list @ . the pc (r15) and lr (r14) cannot both be in the list in an LDM instruction ldm lr, {r0-r12} ldr sp, [lr, #52] ldr lr, [lr, #60] @ restore pc into lr #endif JMP(lr) @ @ static void libunwind::Registers_arm::restoreVFPWithFLDMD(unw_fpreg_t* values) @ @ On entry: @ values pointer is in r0 @ .p2align 2 .fpu vfpv3-d16 DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMDEPy) @ VFP and iwMMX instructions are only available when compiling with the flags @ that enable them. We do not want to do that in the library (because we do not @ want the compiler to generate instructions that access those) but this is @ only accessed if the personality routine needs these registers. Use of @ these registers implies they are, actually, available on the target, so @ it's ok to execute. @ So, generate the instruction using the corresponding coprocessor mnemonic. vldmia r0, {d0-d15} JMP(lr) @ @ static void libunwind::Registers_arm::restoreVFPWithFLDMX(unw_fpreg_t* values) @ @ On entry: @ values pointer is in r0 @ .p2align 2 .fpu vfpv3-d16 DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMXEPy) vldmia r0, {d0-d15} @ fldmiax is deprecated in ARMv7+ and now behaves like vldmia JMP(lr) @ @ static void libunwind::Registers_arm::restoreVFPv3(unw_fpreg_t* values) @ @ On entry: @ values pointer is in r0 @ .p2align 2 .fpu vfpv3 DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreVFPv3EPy) vldmia r0, {d16-d31} JMP(lr) @ @ static void libunwind::Registers_arm::restoreiWMMX(unw_fpreg_t* values) @ @ On entry: @ values pointer is in r0 @ .p2align 2 DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreiWMMXEPy) #if (!defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_6SM__)) || defined(__ARM_WMMX) ldcl p1, cr0, [r0], #8 @ wldrd wR0, [r0], #8 ldcl p1, cr1, [r0], #8 @ wldrd wR1, [r0], #8 ldcl p1, cr2, [r0], #8 @ wldrd wR2, [r0], #8 ldcl p1, cr3, [r0], #8 @ wldrd wR3, [r0], #8 ldcl p1, cr4, [r0], #8 @ wldrd wR4, [r0], #8 ldcl p1, cr5, [r0], #8 @ wldrd wR5, [r0], #8 ldcl p1, cr6, [r0], #8 @ wldrd wR6, [r0], #8 ldcl p1, cr7, [r0], #8 @ wldrd wR7, [r0], #8 ldcl p1, cr8, [r0], #8 @ wldrd wR8, [r0], #8 ldcl p1, cr9, [r0], #8 @ wldrd wR9, [r0], #8 ldcl p1, cr10, [r0], #8 @ wldrd wR10, [r0], #8 ldcl p1, cr11, [r0], #8 @ wldrd wR11, [r0], #8 ldcl p1, cr12, [r0], #8 @ wldrd wR12, [r0], #8 ldcl p1, cr13, [r0], #8 @ wldrd wR13, [r0], #8 ldcl p1, cr14, [r0], #8 @ wldrd wR14, [r0], #8 ldcl p1, cr15, [r0], #8 @ wldrd wR15, [r0], #8 #endif JMP(lr) @ @ static void libunwind::Registers_arm::restoreiWMMXControl(unw_uint32_t* values) @ @ On entry: @ values pointer is in r0 @ .p2align 2 DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreiWMMXControlEPj) #if (!defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_6SM__)) || defined(__ARM_WMMX) ldc2 p1, cr8, [r0], #4 @ wldrw wCGR0, [r0], #4 ldc2 p1, cr9, [r0], #4 @ wldrw wCGR1, [r0], #4 ldc2 p1, cr10, [r0], #4 @ wldrw wCGR2, [r0], #4 ldc2 p1, cr11, [r0], #4 @ wldrw wCGR3, [r0], #4 #endif JMP(lr) #elif defined(__or1k__) DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv) # # void libunwind::Registers_or1k::jumpto() # # On entry: # thread_state pointer is in r3 # # restore integral registerrs l.lwz r0, 0(r3) l.lwz r1, 4(r3) l.lwz r2, 8(r3) # skip r3 for now l.lwz r4, 16(r3) l.lwz r5, 20(r3) l.lwz r6, 24(r3) l.lwz r7, 28(r3) l.lwz r8, 32(r3) l.lwz r9, 36(r3) l.lwz r10, 40(r3) l.lwz r11, 44(r3) l.lwz r12, 48(r3) l.lwz r13, 52(r3) l.lwz r14, 56(r3) l.lwz r15, 60(r3) l.lwz r16, 64(r3) l.lwz r17, 68(r3) l.lwz r18, 72(r3) l.lwz r19, 76(r3) l.lwz r20, 80(r3) l.lwz r21, 84(r3) l.lwz r22, 88(r3) l.lwz r23, 92(r3) l.lwz r24, 96(r3) l.lwz r25,100(r3) l.lwz r26,104(r3) l.lwz r27,108(r3) l.lwz r28,112(r3) l.lwz r29,116(r3) l.lwz r30,120(r3) l.lwz r31,124(r3) # at last, restore r3 l.lwz r3, 12(r3) # jump to pc l.jr r9 l.nop #elif defined(__riscv__) /* RISCVTODO */ #endif Index: head/contrib/llvm/projects/libunwind/src/UnwindRegistersSave.S =================================================================== --- head/contrib/llvm/projects/libunwind/src/UnwindRegistersSave.S (revision 302449) +++ head/contrib/llvm/projects/libunwind/src/UnwindRegistersSave.S (revision 302450) @@ -1,471 +1,471 @@ //===------------------------ UnwindRegistersSave.S -----------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "assembly.h" .text #if defined(__i386__) # # extern int unw_getcontext(unw_context_t* thread_state) # # On entry: # + + # +-----------------------+ # + thread_state pointer + # +-----------------------+ # + return address + # +-----------------------+ <-- SP # + + # DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) push %eax movl 8(%esp), %eax movl %ebx, 4(%eax) movl %ecx, 8(%eax) movl %edx, 12(%eax) movl %edi, 16(%eax) movl %esi, 20(%eax) movl %ebp, 24(%eax) movl %esp, %edx addl $8, %edx movl %edx, 28(%eax) # store what sp was at call site as esp # skip ss # skip eflags movl 4(%esp), %edx movl %edx, 40(%eax) # store return address as eip # skip cs # skip ds # skip es # skip fs # skip gs movl (%esp), %edx movl %edx, (%eax) # store original eax popl %eax xorl %eax, %eax # return UNW_ESUCCESS ret #elif defined(__x86_64__) # # extern int unw_getcontext(unw_context_t* thread_state) # # On entry: # thread_state pointer is in rdi # DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) movq %rax, (%rdi) movq %rbx, 8(%rdi) movq %rcx, 16(%rdi) movq %rdx, 24(%rdi) movq %rdi, 32(%rdi) movq %rsi, 40(%rdi) movq %rbp, 48(%rdi) movq %rsp, 56(%rdi) addq $8, 56(%rdi) movq %r8, 64(%rdi) movq %r9, 72(%rdi) movq %r10, 80(%rdi) movq %r11, 88(%rdi) movq %r12, 96(%rdi) movq %r13,104(%rdi) movq %r14,112(%rdi) movq %r15,120(%rdi) movq (%rsp),%rsi movq %rsi,128(%rdi) # store return address as rip # skip rflags # skip cs # skip fs # skip gs xorl %eax, %eax # return UNW_ESUCCESS ret # elif defined(__mips__) # # extern int unw_getcontext(unw_context_t* thread_state) # # Just trap for the time being. DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) teq $0, $0 #elif defined(__ppc__) ; ; extern int unw_getcontext(unw_context_t* thread_state) ; ; On entry: ; thread_state pointer is in r3 ; DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) stw r0, 8(r3) mflr r0 stw r0, 0(r3) ; store lr as ssr0 stw r1, 12(r3) stw r2, 16(r3) stw r3, 20(r3) stw r4, 24(r3) stw r5, 28(r3) stw r6, 32(r3) stw r7, 36(r3) stw r8, 40(r3) stw r9, 44(r3) stw r10, 48(r3) stw r11, 52(r3) stw r12, 56(r3) stw r13, 60(r3) stw r14, 64(r3) stw r15, 68(r3) stw r16, 72(r3) stw r17, 76(r3) stw r18, 80(r3) stw r19, 84(r3) stw r20, 88(r3) stw r21, 92(r3) stw r22, 96(r3) stw r23,100(r3) stw r24,104(r3) stw r25,108(r3) stw r26,112(r3) stw r27,116(r3) stw r28,120(r3) stw r29,124(r3) stw r30,128(r3) stw r31,132(r3) ; save VRSave register mfspr r0,256 stw r0,156(r3) ; save CR registers mfcr r0 stw r0,136(r3) ; save CTR register mfctr r0 stw r0,148(r3) ; save float registers stfd f0, 160(r3) stfd f1, 168(r3) stfd f2, 176(r3) stfd f3, 184(r3) stfd f4, 192(r3) stfd f5, 200(r3) stfd f6, 208(r3) stfd f7, 216(r3) stfd f8, 224(r3) stfd f9, 232(r3) stfd f10,240(r3) stfd f11,248(r3) stfd f12,256(r3) stfd f13,264(r3) stfd f14,272(r3) stfd f15,280(r3) stfd f16,288(r3) stfd f17,296(r3) stfd f18,304(r3) stfd f19,312(r3) stfd f20,320(r3) stfd f21,328(r3) stfd f22,336(r3) stfd f23,344(r3) stfd f24,352(r3) stfd f25,360(r3) stfd f26,368(r3) stfd f27,376(r3) stfd f28,384(r3) stfd f29,392(r3) stfd f30,400(r3) stfd f31,408(r3) ; save vector registers subi r4,r1,16 rlwinm r4,r4,0,0,27 ; mask low 4-bits ; r4 is now a 16-byte aligned pointer into the red zone #define SAVE_VECTOR_UNALIGNED(_vec, _offset) \ stvx _vec,0,r4 @\ lwz r5, 0(r4) @\ stw r5, _offset(r3) @\ lwz r5, 4(r4) @\ stw r5, _offset+4(r3) @\ lwz r5, 8(r4) @\ stw r5, _offset+8(r3) @\ lwz r5, 12(r4) @\ stw r5, _offset+12(r3) SAVE_VECTOR_UNALIGNED( v0, 424+0x000) SAVE_VECTOR_UNALIGNED( v1, 424+0x010) SAVE_VECTOR_UNALIGNED( v2, 424+0x020) SAVE_VECTOR_UNALIGNED( v3, 424+0x030) SAVE_VECTOR_UNALIGNED( v4, 424+0x040) SAVE_VECTOR_UNALIGNED( v5, 424+0x050) SAVE_VECTOR_UNALIGNED( v6, 424+0x060) SAVE_VECTOR_UNALIGNED( v7, 424+0x070) SAVE_VECTOR_UNALIGNED( v8, 424+0x080) SAVE_VECTOR_UNALIGNED( v9, 424+0x090) SAVE_VECTOR_UNALIGNED(v10, 424+0x0A0) SAVE_VECTOR_UNALIGNED(v11, 424+0x0B0) SAVE_VECTOR_UNALIGNED(v12, 424+0x0C0) SAVE_VECTOR_UNALIGNED(v13, 424+0x0D0) SAVE_VECTOR_UNALIGNED(v14, 424+0x0E0) SAVE_VECTOR_UNALIGNED(v15, 424+0x0F0) SAVE_VECTOR_UNALIGNED(v16, 424+0x100) SAVE_VECTOR_UNALIGNED(v17, 424+0x110) SAVE_VECTOR_UNALIGNED(v18, 424+0x120) SAVE_VECTOR_UNALIGNED(v19, 424+0x130) SAVE_VECTOR_UNALIGNED(v20, 424+0x140) SAVE_VECTOR_UNALIGNED(v21, 424+0x150) SAVE_VECTOR_UNALIGNED(v22, 424+0x160) SAVE_VECTOR_UNALIGNED(v23, 424+0x170) SAVE_VECTOR_UNALIGNED(v24, 424+0x180) SAVE_VECTOR_UNALIGNED(v25, 424+0x190) SAVE_VECTOR_UNALIGNED(v26, 424+0x1A0) SAVE_VECTOR_UNALIGNED(v27, 424+0x1B0) SAVE_VECTOR_UNALIGNED(v28, 424+0x1C0) SAVE_VECTOR_UNALIGNED(v29, 424+0x1D0) SAVE_VECTOR_UNALIGNED(v30, 424+0x1E0) SAVE_VECTOR_UNALIGNED(v31, 424+0x1F0) li r3, 0 ; return UNW_ESUCCESS blr #elif defined(__arm64__) || defined(__aarch64__) // // extern int unw_getcontext(unw_context_t* thread_state) // // On entry: // thread_state pointer is in x0 // .p2align 2 DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) stp x0, x1, [x0, #0x000] stp x2, x3, [x0, #0x010] stp x4, x5, [x0, #0x020] stp x6, x7, [x0, #0x030] stp x8, x9, [x0, #0x040] stp x10,x11, [x0, #0x050] stp x12,x13, [x0, #0x060] stp x14,x15, [x0, #0x070] stp x16,x17, [x0, #0x080] stp x18,x19, [x0, #0x090] stp x20,x21, [x0, #0x0A0] stp x22,x23, [x0, #0x0B0] stp x24,x25, [x0, #0x0C0] stp x26,x27, [x0, #0x0D0] - stp x28,fp, [x0, #0x0E0] - str lr, [x0, #0x0F0] + stp x28,x29, [x0, #0x0E0] + str x30, [x0, #0x0F0] mov x1,sp str x1, [x0, #0x0F8] - str lr, [x0, #0x100] // store return address as pc + str x30, [x0, #0x100] // store return address as pc // skip cpsr stp d0, d1, [x0, #0x110] stp d2, d3, [x0, #0x120] stp d4, d5, [x0, #0x130] stp d6, d7, [x0, #0x140] stp d8, d9, [x0, #0x150] stp d10,d11, [x0, #0x160] stp d12,d13, [x0, #0x170] stp d14,d15, [x0, #0x180] stp d16,d17, [x0, #0x190] stp d18,d19, [x0, #0x1A0] stp d20,d21, [x0, #0x1B0] stp d22,d23, [x0, #0x1C0] stp d24,d25, [x0, #0x1D0] stp d26,d27, [x0, #0x1E0] stp d28,d29, [x0, #0x1F0] str d30, [x0, #0x200] str d31, [x0, #0x208] mov x0, #0 // return UNW_ESUCCESS ret #elif defined(__arm__) && !defined(__APPLE__) #if !defined(__ARM_ARCH_ISA_ARM) .thumb #endif @ @ extern int unw_getcontext(unw_context_t* thread_state) @ @ On entry: @ thread_state pointer is in r0 @ @ Per EHABI #4.7 this only saves the core integer registers. @ EHABI #7.4.5 notes that in general all VRS registers should be restored @ however this is very hard to do for VFP registers because it is unknown @ to the library how many registers are implemented by the architecture. @ Instead, VFP registers are demand saved by logic external to unw_getcontext. @ .p2align 2 DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) #if !defined(__ARM_ARCH_ISA_ARM) stm r0, {r0-r7} mov r2, sp mov r3, lr str r2, [r0, #52] str r3, [r0, #56] str r3, [r0, #60] @ store return address as pc #else @ 32bit thumb-2 restrictions for stm: @ . the sp (r13) cannot be in the list @ . the pc (r15) cannot be in the list in an STM instruction stm r0, {r0-r12} str sp, [r0, #52] str lr, [r0, #56] str lr, [r0, #60] @ store return address as pc #endif #if __ARM_ARCH_ISA_THUMB == 1 @ T1 does not have a non-cpsr-clobbering register-zeroing instruction. @ It is safe to use here though because we are about to return, and cpsr is @ not expected to be preserved. movs r0, #0 @ return UNW_ESUCCESS #else mov r0, #0 @ return UNW_ESUCCESS #endif JMP(lr) @ @ static void libunwind::Registers_arm::saveVFPWithFSTMD(unw_fpreg_t* values) @ @ On entry: @ values pointer is in r0 @ .p2align 2 .fpu vfpv3-d16 DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMDEPy) vstmia r0, {d0-d15} JMP(lr) @ @ static void libunwind::Registers_arm::saveVFPWithFSTMX(unw_fpreg_t* values) @ @ On entry: @ values pointer is in r0 @ .p2align 2 .fpu vfpv3-d16 DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMXEPy) vstmia r0, {d0-d15} @ fstmiax is deprecated in ARMv7+ and now behaves like vstmia JMP(lr) @ @ static void libunwind::Registers_arm::saveVFPv3(unw_fpreg_t* values) @ @ On entry: @ values pointer is in r0 @ .p2align 2 .fpu vfpv3 DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveVFPv3EPy) @ VFP and iwMMX instructions are only available when compiling with the flags @ that enable them. We do not want to do that in the library (because we do not @ want the compiler to generate instructions that access those) but this is @ only accessed if the personality routine needs these registers. Use of @ these registers implies they are, actually, available on the target, so @ it's ok to execute. @ So, generate the instructions using the corresponding coprocessor mnemonic. vstmia r0, {d16-d31} JMP(lr) @ @ static void libunwind::Registers_arm::saveiWMMX(unw_fpreg_t* values) @ @ On entry: @ values pointer is in r0 @ .p2align 2 DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveiWMMXEPy) #if (!defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_6SM__)) || defined(__ARM_WMMX) stcl p1, cr0, [r0], #8 @ wstrd wR0, [r0], #8 stcl p1, cr1, [r0], #8 @ wstrd wR1, [r0], #8 stcl p1, cr2, [r0], #8 @ wstrd wR2, [r0], #8 stcl p1, cr3, [r0], #8 @ wstrd wR3, [r0], #8 stcl p1, cr4, [r0], #8 @ wstrd wR4, [r0], #8 stcl p1, cr5, [r0], #8 @ wstrd wR5, [r0], #8 stcl p1, cr6, [r0], #8 @ wstrd wR6, [r0], #8 stcl p1, cr7, [r0], #8 @ wstrd wR7, [r0], #8 stcl p1, cr8, [r0], #8 @ wstrd wR8, [r0], #8 stcl p1, cr9, [r0], #8 @ wstrd wR9, [r0], #8 stcl p1, cr10, [r0], #8 @ wstrd wR10, [r0], #8 stcl p1, cr11, [r0], #8 @ wstrd wR11, [r0], #8 stcl p1, cr12, [r0], #8 @ wstrd wR12, [r0], #8 stcl p1, cr13, [r0], #8 @ wstrd wR13, [r0], #8 stcl p1, cr14, [r0], #8 @ wstrd wR14, [r0], #8 stcl p1, cr15, [r0], #8 @ wstrd wR15, [r0], #8 #endif JMP(lr) @ @ static void libunwind::Registers_arm::saveiWMMXControl(unw_uint32_t* values) @ @ On entry: @ values pointer is in r0 @ .p2align 2 DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveiWMMXControlEPj) #if (!defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_6SM__)) || defined(__ARM_WMMX) stc2 p1, cr8, [r0], #4 @ wstrw wCGR0, [r0], #4 stc2 p1, cr9, [r0], #4 @ wstrw wCGR1, [r0], #4 stc2 p1, cr10, [r0], #4 @ wstrw wCGR2, [r0], #4 stc2 p1, cr11, [r0], #4 @ wstrw wCGR3, [r0], #4 #endif JMP(lr) #elif defined(__or1k__) # # extern int unw_getcontext(unw_context_t* thread_state) # # On entry: # thread_state pointer is in r3 # DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) l.sw 0(r3), r0 l.sw 4(r3), r1 l.sw 8(r3), r2 l.sw 12(r3), r3 l.sw 16(r3), r4 l.sw 20(r3), r5 l.sw 24(r3), r6 l.sw 28(r3), r7 l.sw 32(r3), r8 l.sw 36(r3), r9 l.sw 40(r3), r10 l.sw 44(r3), r11 l.sw 48(r3), r12 l.sw 52(r3), r13 l.sw 56(r3), r14 l.sw 60(r3), r15 l.sw 64(r3), r16 l.sw 68(r3), r17 l.sw 72(r3), r18 l.sw 76(r3), r19 l.sw 80(r3), r20 l.sw 84(r3), r21 l.sw 88(r3), r22 l.sw 92(r3), r23 l.sw 96(r3), r24 l.sw 100(r3), r25 l.sw 104(r3), r26 l.sw 108(r3), r27 l.sw 112(r3), r28 l.sw 116(r3), r29 l.sw 120(r3), r30 l.sw 124(r3), r31 #elif defined(__riscv__) /* RISCVTODO */ #endif Index: head/contrib/llvm/projects/libunwind/src/config.h =================================================================== --- head/contrib/llvm/projects/libunwind/src/config.h (revision 302449) +++ head/contrib/llvm/projects/libunwind/src/config.h (revision 302450) @@ -1,129 +1,144 @@ //===----------------------------- config.h -------------------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // // // Defines macros used within libuwind project. // //===----------------------------------------------------------------------===// #ifndef LIBUNWIND_CONFIG_H #define LIBUNWIND_CONFIG_H #include #include +#include // Define static_assert() unless already defined by compiler. #ifndef __has_feature #define __has_feature(__x) 0 #endif #if !(__has_feature(cxx_static_assert)) && !defined(static_assert) #define static_assert(__b, __m) \ extern int compile_time_assert_failed[ ( __b ) ? 1 : -1 ] \ __attribute__( ( unused ) ); #endif // Platform specific configuration defines. #ifdef __APPLE__ - #include - #ifdef __cplusplus - extern "C" { - #endif - void __assert_rtn(const char *, const char *, int, const char *) - __attribute__((noreturn)); - #ifdef __cplusplus - } - #endif - - #define _LIBUNWIND_BUILD_ZERO_COST_APIS (defined(__i386__) || \ - defined(__x86_64__) || \ - defined(__arm64__) || \ - defined(__mips__)) - #define _LIBUNWIND_BUILD_SJLJ_APIS defined(__arm__) - #define _LIBUNWIND_SUPPORT_FRAME_APIS (defined(__i386__) || \ - defined(__x86_64__)) - #define _LIBUNWIND_EXPORT __attribute__((visibility("default"))) - #define _LIBUNWIND_HIDDEN __attribute__((visibility("hidden"))) - #define _LIBUNWIND_LOG(msg, ...) fprintf(stderr, "libuwind: " msg, __VA_ARGS__) - #define _LIBUNWIND_ABORT(msg) __assert_rtn(__func__, __FILE__, __LINE__, msg) - #if defined(FOR_DYLD) #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1 #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 0 #define _LIBUNWIND_SUPPORT_DWARF_INDEX 0 #else #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1 #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 #define _LIBUNWIND_SUPPORT_DWARF_INDEX 0 #endif - #else - #include + #if defined(__ARM_DWARF_EH__) || !defined(__arm__) + #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 0 + #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 + #define _LIBUNWIND_SUPPORT_DWARF_INDEX 1 + #else + #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 0 + #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 0 + #define _LIBUNWIND_SUPPORT_DWARF_INDEX 0 + #endif +#endif - static inline void assert_rtn(const char* func, const char* file, int line, const char* msg) __attribute__ ((noreturn)); - static inline void assert_rtn(const char* func, const char* file, int line, const char* msg) { - fprintf(stderr, "libunwind: %s %s:%d - %s\n", func, file, line, msg); - assert(false); - abort(); - } +// FIXME: these macros are not correct for COFF targets +#define _LIBUNWIND_EXPORT __attribute__((visibility("default"))) +#define _LIBUNWIND_HIDDEN __attribute__((visibility("hidden"))) - #define _LIBUNWIND_BUILD_ZERO_COST_APIS (defined(__i386__) || \ - defined(__x86_64__) || \ - defined(__arm__) || \ - defined(__aarch64__) || \ - defined(__riscv__)) - #define _LIBUNWIND_BUILD_SJLJ_APIS 0 - #define _LIBUNWIND_SUPPORT_FRAME_APIS (defined(__i386__) || \ - defined(__x86_64__)) - #define _LIBUNWIND_EXPORT __attribute__((visibility("default"))) - #define _LIBUNWIND_HIDDEN __attribute__((visibility("hidden"))) - #define _LIBUNWIND_LOG(msg, ...) fprintf(stderr, "libuwind: " msg, __VA_ARGS__) - #define _LIBUNWIND_ABORT(msg) assert_rtn(__func__, __FILE__, __LINE__, msg) +#if (defined(__APPLE__) && defined(__arm__)) || defined(__USING_SJLJ_EXCEPTIONS__) +#define _LIBUNWIND_BUILD_SJLJ_APIS 1 +#else +#define _LIBUNWIND_BUILD_SJLJ_APIS 0 +#endif - #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 0 - #define _LIBUNWIND_SUPPORT_DWARF_UNWIND !defined(__arm__) || \ - defined(__ARM_DWARF_EH__) - #define _LIBUNWIND_SUPPORT_DWARF_INDEX _LIBUNWIND_SUPPORT_DWARF_UNWIND +#if defined(__i386__) || defined(__x86_64__) +#define _LIBUNWIND_SUPPORT_FRAME_APIS 1 +#else +#define _LIBUNWIND_SUPPORT_FRAME_APIS 0 #endif +#if defined(__i386__) || defined(__x86_64__) || \ + (!defined(__APPLE__) && defined(__arm__)) || \ + (defined(__arm64__) || defined(__aarch64__)) || \ + (defined(__APPLE__) && defined(__mips__)) || \ + defined(__riscv__) +#define _LIBUNWIND_BUILD_ZERO_COST_APIS 1 +#else +#define _LIBUNWIND_BUILD_ZERO_COST_APIS 0 +#endif +#define _LIBUNWIND_ABORT(msg) \ + do { \ + fprintf(stderr, "libunwind: %s %s:%d - %s\n", __func__, __FILE__, \ + __LINE__, msg); \ + fflush(stderr); \ + abort(); \ + } while (0) +#define _LIBUNWIND_LOG(msg, ...) fprintf(stderr, "libuwind: " msg, __VA_ARGS__) + // Macros that define away in non-Debug builds #ifdef NDEBUG #define _LIBUNWIND_DEBUG_LOG(msg, ...) #define _LIBUNWIND_TRACE_API(msg, ...) #define _LIBUNWIND_TRACING_UNWINDING 0 #define _LIBUNWIND_TRACE_UNWINDING(msg, ...) #define _LIBUNWIND_LOG_NON_ZERO(x) x #else #ifdef __cplusplus extern "C" { #endif extern bool logAPIs(); extern bool logUnwinding(); #ifdef __cplusplus } #endif #define _LIBUNWIND_DEBUG_LOG(msg, ...) _LIBUNWIND_LOG(msg, __VA_ARGS__) #define _LIBUNWIND_LOG_NON_ZERO(x) \ do { \ int _err = x; \ if ( _err != 0 ) \ _LIBUNWIND_LOG("" #x "=%d in %s", _err, __FUNCTION__); \ } while (0) #define _LIBUNWIND_TRACE_API(msg, ...) \ do { \ if ( logAPIs() ) _LIBUNWIND_LOG(msg, __VA_ARGS__); \ } while(0) #define _LIBUNWIND_TRACE_UNWINDING(msg, ...) \ do { \ if ( logUnwinding() ) _LIBUNWIND_LOG(msg, __VA_ARGS__); \ } while(0) #define _LIBUNWIND_TRACING_UNWINDING logUnwinding() #endif +#ifdef __cplusplus +// Used to fit UnwindCursor and Registers_xxx types against unw_context_t / +// unw_cursor_t sized memory blocks. +#if defined(_LIBUNWIND_IS_NATIVE_ONLY) +# define COMP_OP == +#else +# define COMP_OP < +#endif +template +struct check_fit { + template + struct blk_count { + static const size_t count = + (sizeof(T) + sizeof(uint64_t) - 1) / sizeof(uint64_t); + }; + static const bool does_fit = + (blk_count<_Type>::count COMP_OP blk_count<_Mem>::count); +}; +#undef COMP_OP +#endif // __cplusplus #endif // LIBUNWIND_CONFIG_H Index: head/contrib/llvm/projects/libunwind/src/libunwind.cpp =================================================================== --- head/contrib/llvm/projects/libunwind/src/libunwind.cpp (revision 302449) +++ head/contrib/llvm/projects/libunwind/src/libunwind.cpp (revision 302450) @@ -1,381 +1,377 @@ //===--------------------------- libuwind.cpp -----------------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // // // Implements unw_* functions from // //===----------------------------------------------------------------------===// #include #ifndef NDEBUG #include // getenv #endif #include #include #include "libunwind_ext.h" #include "config.h" #include #include "UnwindCursor.hpp" using namespace libunwind; /// internal object to represent this processes address space LocalAddressSpace LocalAddressSpace::sThisAddressSpace; _LIBUNWIND_EXPORT unw_addr_space_t unw_local_addr_space = (unw_addr_space_t)&LocalAddressSpace::sThisAddressSpace; /// record the registers and stack position of the caller extern int unw_getcontext(unw_context_t *); // note: unw_getcontext() implemented in assembly /// Create a cursor of a thread in this process given 'context' recorded by /// unw_getcontext(). _LIBUNWIND_EXPORT int unw_init_local(unw_cursor_t *cursor, unw_context_t *context) { _LIBUNWIND_TRACE_API("unw_init_local(cursor=%p, context=%p)\n", static_cast(cursor), static_cast(context)); - // Use "placement new" to allocate UnwindCursor in the cursor buffer. #if defined(__i386__) - new ((void *)cursor) UnwindCursor( - context, LocalAddressSpace::sThisAddressSpace); +# define REGISTER_KIND Registers_x86 #elif defined(__x86_64__) - new ((void *)cursor) UnwindCursor( - context, LocalAddressSpace::sThisAddressSpace); +# define REGISTER_KIND Registers_x86_64 #elif defined(__ppc__) - new ((void *)cursor) UnwindCursor( - context, LocalAddressSpace::sThisAddressSpace); -#elif defined(__arm64__) || defined(__aarch64__) - new ((void *)cursor) UnwindCursor( - context, LocalAddressSpace::sThisAddressSpace); +# define REGISTER_KIND Registers_ppc +#elif defined(__aarch64__) +# define REGISTER_KIND Registers_arm64 #elif _LIBUNWIND_ARM_EHABI - new ((void *)cursor) UnwindCursor( - context, LocalAddressSpace::sThisAddressSpace); +# define REGISTER_KIND Registers_arm #elif defined(__or1k__) - new ((void *)cursor) UnwindCursor( - context, LocalAddressSpace::sThisAddressSpace); -#elif defined(__mips__) -#warning The MIPS architecture is not supported. +# define REGISTER_KIND Registers_or1k #elif defined(__riscv__) - new ((void *)cursor) UnwindCursor( - context, LocalAddressSpace::sThisAddressSpace); +# define REGISTER_KIND Registers_riscv +#elif defined(__mips__) +# warning The MIPS architecture is not supported. #else -#error Architecture not supported +# error Architecture not supported #endif + // Use "placement new" to allocate UnwindCursor in the cursor buffer. + new ((void *)cursor) UnwindCursor( + context, LocalAddressSpace::sThisAddressSpace); +#undef REGISTER_KIND AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; co->setInfoBasedOnIPRegister(); return UNW_ESUCCESS; } #ifdef UNW_REMOTE /// Create a cursor into a thread in another process. _LIBUNWIND_EXPORT int unw_init_remote_thread(unw_cursor_t *cursor, unw_addr_space_t as, void *arg) { // special case: unw_init_remote(xx, unw_local_addr_space, xx) if (as == (unw_addr_space_t)&LocalAddressSpace::sThisAddressSpace) return unw_init_local(cursor, NULL); //FIXME // use "placement new" to allocate UnwindCursor in the cursor buffer switch (as->cpuType) { case CPU_TYPE_I386: new ((void *)cursor) UnwindCursor >, Registers_x86>(((unw_addr_space_i386 *)as)->oas, arg); break; case CPU_TYPE_X86_64: new ((void *)cursor) UnwindCursor< OtherAddressSpace >, Registers_x86_64>( ((unw_addr_space_x86_64 *)as)->oas, arg); break; case CPU_TYPE_POWERPC: new ((void *)cursor) UnwindCursor >, Registers_ppc>( ((unw_addr_space_ppc *)as)->oas, arg); break; default: return UNW_EUNSPEC; } return UNW_ESUCCESS; } static bool is64bit(task_t task) { return false; // FIXME } /// Create an address_space object for use in examining another task. _LIBUNWIND_EXPORT unw_addr_space_t unw_create_addr_space_for_task(task_t task) { #if __i386__ if (is64bit(task)) { unw_addr_space_x86_64 *as = new unw_addr_space_x86_64(task); as->taskPort = task; as->cpuType = CPU_TYPE_X86_64; //as->oas } else { unw_addr_space_i386 *as = new unw_addr_space_i386(task); as->taskPort = task; as->cpuType = CPU_TYPE_I386; //as->oas } #else // FIXME #endif } /// Delete an address_space object. _LIBUNWIND_EXPORT void unw_destroy_addr_space(unw_addr_space_t asp) { switch (asp->cpuType) { #if __i386__ || __x86_64__ case CPU_TYPE_I386: { unw_addr_space_i386 *as = (unw_addr_space_i386 *)asp; delete as; } break; case CPU_TYPE_X86_64: { unw_addr_space_x86_64 *as = (unw_addr_space_x86_64 *)asp; delete as; } break; #endif case CPU_TYPE_POWERPC: { unw_addr_space_ppc *as = (unw_addr_space_ppc *)asp; delete as; } break; } } #endif // UNW_REMOTE /// Get value of specified register at cursor position in stack frame. _LIBUNWIND_EXPORT int unw_get_reg(unw_cursor_t *cursor, unw_regnum_t regNum, unw_word_t *value) { _LIBUNWIND_TRACE_API("unw_get_reg(cursor=%p, regNum=%d, &value=%p)\n", static_cast(cursor), regNum, static_cast(value)); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; if (co->validReg(regNum)) { *value = co->getReg(regNum); return UNW_ESUCCESS; } return UNW_EBADREG; } /// Set value of specified register at cursor position in stack frame. _LIBUNWIND_EXPORT int unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum, unw_word_t value) { _LIBUNWIND_TRACE_API("unw_set_reg(cursor=%p, regNum=%d, value=0x%llX)\n", static_cast(cursor), regNum, (long long)value); typedef LocalAddressSpace::pint_t pint_t; AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; if (co->validReg(regNum)) { co->setReg(regNum, (pint_t)value); // specical case altering IP to re-find info (being called by personality // function) if (regNum == UNW_REG_IP) co->setInfoBasedOnIPRegister(false); return UNW_ESUCCESS; } return UNW_EBADREG; } /// Get value of specified float register at cursor position in stack frame. _LIBUNWIND_EXPORT int unw_get_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum, unw_fpreg_t *value) { _LIBUNWIND_TRACE_API("unw_get_fpreg(cursor=%p, regNum=%d, &value=%p)\n", static_cast(cursor), regNum, static_cast(value)); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; if (co->validFloatReg(regNum)) { *value = co->getFloatReg(regNum); return UNW_ESUCCESS; } return UNW_EBADREG; } /// Set value of specified float register at cursor position in stack frame. _LIBUNWIND_EXPORT int unw_set_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum, unw_fpreg_t value) { #if _LIBUNWIND_ARM_EHABI _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%llX)\n", static_cast(cursor), regNum, value); #else _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%g)\n", static_cast(cursor), regNum, value); #endif AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; if (co->validFloatReg(regNum)) { co->setFloatReg(regNum, value); return UNW_ESUCCESS; } return UNW_EBADREG; } /// Move cursor to next frame. _LIBUNWIND_EXPORT int unw_step(unw_cursor_t *cursor) { _LIBUNWIND_TRACE_API("unw_step(cursor=%p)\n", static_cast(cursor)); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; return co->step(); } /// Get unwind info at cursor position in stack frame. _LIBUNWIND_EXPORT int unw_get_proc_info(unw_cursor_t *cursor, unw_proc_info_t *info) { _LIBUNWIND_TRACE_API("unw_get_proc_info(cursor=%p, &info=%p)\n", static_cast(cursor), static_cast(info)); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; co->getInfo(info); if (info->end_ip == 0) return UNW_ENOINFO; else return UNW_ESUCCESS; } /// Resume execution at cursor position (aka longjump). _LIBUNWIND_EXPORT int unw_resume(unw_cursor_t *cursor) { _LIBUNWIND_TRACE_API("unw_resume(cursor=%p)\n", static_cast(cursor)); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; co->jumpto(); return UNW_EUNSPEC; } /// Get name of function at cursor position in stack frame. _LIBUNWIND_EXPORT int unw_get_proc_name(unw_cursor_t *cursor, char *buf, size_t bufLen, unw_word_t *offset) { _LIBUNWIND_TRACE_API("unw_get_proc_name(cursor=%p, &buf=%p, bufLen=%lu)\n", static_cast(cursor), static_cast(buf), static_cast(bufLen)); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; if (co->getFunctionName(buf, bufLen, offset)) return UNW_ESUCCESS; else return UNW_EUNSPEC; } /// Checks if a register is a floating-point register. _LIBUNWIND_EXPORT int unw_is_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum) { _LIBUNWIND_TRACE_API("unw_is_fpreg(cursor=%p, regNum=%d)\n", static_cast(cursor), regNum); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; return co->validFloatReg(regNum); } /// Checks if a register is a floating-point register. _LIBUNWIND_EXPORT const char *unw_regname(unw_cursor_t *cursor, unw_regnum_t regNum) { _LIBUNWIND_TRACE_API("unw_regname(cursor=%p, regNum=%d)\n", static_cast(cursor), regNum); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; return co->getRegisterName(regNum); } /// Checks if current frame is signal trampoline. _LIBUNWIND_EXPORT int unw_is_signal_frame(unw_cursor_t *cursor) { _LIBUNWIND_TRACE_API("unw_is_signal_frame(cursor=%p)\n", static_cast(cursor)); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; return co->isSignalFrame(); } #ifdef __arm__ // Save VFP registers d0-d15 using FSTMIADX instead of FSTMIADD _LIBUNWIND_EXPORT void unw_save_vfp_as_X(unw_cursor_t *cursor) { _LIBUNWIND_TRACE_API("unw_fpreg_save_vfp_as_X(cursor=%p)\n", static_cast(cursor)); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; return co->saveVFPAsX(); } #endif #if _LIBUNWIND_SUPPORT_DWARF_UNWIND /// SPI: walks cached dwarf entries _LIBUNWIND_EXPORT void unw_iterate_dwarf_unwind_cache(void (*func)( unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) { _LIBUNWIND_TRACE_API("unw_iterate_dwarf_unwind_cache(func=%p)\n", reinterpret_cast(func)); DwarfFDECache::iterateCacheEntries(func); } /// IPI: for __register_frame() void _unw_add_dynamic_fde(unw_word_t fde) { CFI_Parser::FDE_Info fdeInfo; CFI_Parser::CIE_Info cieInfo; const char *message = CFI_Parser::decodeFDE( LocalAddressSpace::sThisAddressSpace, (LocalAddressSpace::pint_t) fde, &fdeInfo, &cieInfo); if (message == NULL) { // dynamically registered FDEs don't have a mach_header group they are in. // Use fde as mh_group unw_word_t mh_group = fdeInfo.fdeStart; DwarfFDECache::add((LocalAddressSpace::pint_t)mh_group, fdeInfo.pcStart, fdeInfo.pcEnd, fdeInfo.fdeStart); } else { _LIBUNWIND_DEBUG_LOG("_unw_add_dynamic_fde: bad fde: %s", message); } } /// IPI: for __deregister_frame() void _unw_remove_dynamic_fde(unw_word_t fde) { // fde is own mh_group DwarfFDECache::removeAllIn((LocalAddressSpace::pint_t)fde); } #endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND // Add logging hooks in Debug builds only #ifndef NDEBUG #include _LIBUNWIND_HIDDEN bool logAPIs() { // do manual lock to avoid use of _cxa_guard_acquire or initializers static bool checked = false; static bool log = false; if (!checked) { log = (getenv("LIBUNWIND_PRINT_APIS") != NULL); checked = true; } return log; } _LIBUNWIND_HIDDEN bool logUnwinding() { // do manual lock to avoid use of _cxa_guard_acquire or initializers static bool checked = false; static bool log = false; if (!checked) { log = (getenv("LIBUNWIND_PRINT_UNWINDING") != NULL); checked = true; } return log; } #endif // NDEBUG Index: head/contrib/llvm/projects/libunwind =================================================================== --- head/contrib/llvm/projects/libunwind (revision 302449) +++ head/contrib/llvm/projects/libunwind (revision 302450) Property changes on: head/contrib/llvm/projects/libunwind ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /vendor/llvm-libunwind/dist:r302347