diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2021-02-16 20:13:02 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2021-02-16 20:13:02 +0000 |
commit | b60736ec1405bb0a8dd40989f67ef4c93da068ab (patch) | |
tree | 5c43fbb7c9fc45f0f87e0e6795a86267dbd12f9d /libunwind | |
parent | cfca06d7963fa0909f90483b42a6d7d194d01e08 (diff) | |
download | src-b60736ec1405bb0a8dd40989f67ef4c93da068ab.tar.gz src-b60736ec1405bb0a8dd40989f67ef4c93da068ab.zip |
Vendor import of llvm-project main 8e464dd76bef, the last commit beforevendor/llvm-project/llvmorg-12-init-17869-g8e464dd76bef
the upstream release/12.x branch was created.
Diffstat (limited to 'libunwind')
-rw-r--r-- | libunwind/include/__libunwind_config.h | 10 | ||||
-rw-r--r-- | libunwind/include/libunwind.h | 160 | ||||
-rw-r--r-- | libunwind/src/AddressSpace.hpp | 265 | ||||
-rw-r--r-- | libunwind/src/DwarfInstructions.hpp | 9 | ||||
-rw-r--r-- | libunwind/src/DwarfParser.hpp | 811 | ||||
-rw-r--r-- | libunwind/src/FrameHeaderCache.hpp | 2 | ||||
-rw-r--r-- | libunwind/src/Registers.hpp | 458 | ||||
-rw-r--r-- | libunwind/src/Unwind-seh.cpp | 20 | ||||
-rw-r--r-- | libunwind/src/Unwind-sjlj.c | 12 | ||||
-rw-r--r-- | libunwind/src/UnwindCursor.hpp | 225 | ||||
-rw-r--r-- | libunwind/src/UnwindLevel1.c | 4 | ||||
-rw-r--r-- | libunwind/src/UnwindRegistersRestore.S | 25 | ||||
-rw-r--r-- | libunwind/src/UnwindRegistersSave.S | 9 | ||||
-rw-r--r-- | libunwind/src/Unwind_AppleExtras.cpp | 70 | ||||
-rw-r--r-- | libunwind/src/assembly.h | 24 | ||||
-rw-r--r-- | libunwind/src/config.h | 54 | ||||
-rw-r--r-- | libunwind/src/libunwind.cpp | 2 |
17 files changed, 1396 insertions, 764 deletions
diff --git a/libunwind/include/__libunwind_config.h b/libunwind/include/__libunwind_config.h index 71d77ca65118..34ac6f717d6e 100644 --- a/libunwind/include/__libunwind_config.h +++ b/libunwind/include/__libunwind_config.h @@ -25,8 +25,12 @@ #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC 31 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_HEXAGON 34 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV 64 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_VE 143 #if defined(_LIBUNWIND_IS_NATIVE_ONLY) +# if defined(__linux__) +# define _LIBUNWIND_TARGET_LINUX 1 +# endif # if defined(__i386__) # define _LIBUNWIND_TARGET_I386 # define _LIBUNWIND_CONTEXT_SIZE 8 @@ -135,6 +139,11 @@ # error "Unsupported RISC-V ABI" # endif # define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV +# elif defined(__ve__) +# define _LIBUNWIND_TARGET_VE 1 +# define _LIBUNWIND_CONTEXT_SIZE 67 +# define _LIBUNWIND_CURSOR_SIZE 79 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_VE # else # error "Unsupported architecture." # endif @@ -151,6 +160,7 @@ # define _LIBUNWIND_TARGET_SPARC 1 # define _LIBUNWIND_TARGET_HEXAGON 1 # define _LIBUNWIND_TARGET_RISCV 1 +# define _LIBUNWIND_TARGET_VE 1 # define _LIBUNWIND_CONTEXT_SIZE 167 # define _LIBUNWIND_CURSOR_SIZE 179 # define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287 diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h index 23ef47f4ac83..5bae8d02f799 100644 --- a/libunwind/include/libunwind.h +++ b/libunwind/include/libunwind.h @@ -43,6 +43,12 @@ #define LIBUNWIND_AVAIL #endif +#if defined(_WIN32) && defined(__SEH__) + #define LIBUNWIND_CURSOR_ALIGNMENT_ATTR __attribute__((__aligned__(16))) +#else + #define LIBUNWIND_CURSOR_ALIGNMENT_ATTR +#endif + /* error codes */ enum { UNW_ESUCCESS = 0, /* no error */ @@ -68,7 +74,7 @@ typedef struct unw_context_t unw_context_t; struct unw_cursor_t { uint64_t data[_LIBUNWIND_CURSOR_SIZE]; -}; +} LIBUNWIND_CURSOR_ALIGNMENT_ATTR; typedef struct unw_cursor_t unw_cursor_t; typedef struct unw_addr_space *unw_addr_space_t; @@ -941,4 +947,156 @@ enum { UNW_RISCV_F31 = 63, }; +// VE register numbers +enum { + UNW_VE_S0 = 0, + UNW_VE_S1 = 1, + UNW_VE_S2 = 2, + UNW_VE_S3 = 3, + UNW_VE_S4 = 4, + UNW_VE_S5 = 5, + UNW_VE_S6 = 6, + UNW_VE_S7 = 7, + UNW_VE_S8 = 8, + UNW_VE_S9 = 9, + UNW_VE_S10 = 10, + UNW_VE_S11 = 11, + UNW_VE_S12 = 12, + UNW_VE_S13 = 13, + UNW_VE_S14 = 14, + UNW_VE_S15 = 15, + UNW_VE_S16 = 16, + UNW_VE_S17 = 17, + UNW_VE_S18 = 18, + UNW_VE_S19 = 19, + UNW_VE_S20 = 20, + UNW_VE_S21 = 21, + UNW_VE_S22 = 22, + UNW_VE_S23 = 23, + UNW_VE_S24 = 24, + UNW_VE_S25 = 25, + UNW_VE_S26 = 26, + UNW_VE_S27 = 27, + UNW_VE_S28 = 28, + UNW_VE_S29 = 29, + UNW_VE_S30 = 30, + UNW_VE_S31 = 31, + UNW_VE_S32 = 32, + UNW_VE_S33 = 33, + UNW_VE_S34 = 34, + UNW_VE_S35 = 35, + UNW_VE_S36 = 36, + UNW_VE_S37 = 37, + UNW_VE_S38 = 38, + UNW_VE_S39 = 39, + UNW_VE_S40 = 40, + UNW_VE_S41 = 41, + UNW_VE_S42 = 42, + UNW_VE_S43 = 43, + UNW_VE_S44 = 44, + UNW_VE_S45 = 45, + UNW_VE_S46 = 46, + UNW_VE_S47 = 47, + UNW_VE_S48 = 48, + UNW_VE_S49 = 49, + UNW_VE_S50 = 50, + UNW_VE_S51 = 51, + UNW_VE_S52 = 52, + UNW_VE_S53 = 53, + UNW_VE_S54 = 54, + UNW_VE_S55 = 55, + UNW_VE_S56 = 56, + UNW_VE_S57 = 57, + UNW_VE_S58 = 58, + UNW_VE_S59 = 59, + UNW_VE_S60 = 60, + UNW_VE_S61 = 61, + UNW_VE_S62 = 62, + UNW_VE_S63 = 63, + UNW_VE_V0 = 64 + 0, + UNW_VE_V1 = 64 + 1, + UNW_VE_V2 = 64 + 2, + UNW_VE_V3 = 64 + 3, + UNW_VE_V4 = 64 + 4, + UNW_VE_V5 = 64 + 5, + UNW_VE_V6 = 64 + 6, + UNW_VE_V7 = 64 + 7, + UNW_VE_V8 = 64 + 8, + UNW_VE_V9 = 64 + 9, + UNW_VE_V10 = 64 + 10, + UNW_VE_V11 = 64 + 11, + UNW_VE_V12 = 64 + 12, + UNW_VE_V13 = 64 + 13, + UNW_VE_V14 = 64 + 14, + UNW_VE_V15 = 64 + 15, + UNW_VE_V16 = 64 + 16, + UNW_VE_V17 = 64 + 17, + UNW_VE_V18 = 64 + 18, + UNW_VE_V19 = 64 + 19, + UNW_VE_V20 = 64 + 20, + UNW_VE_V21 = 64 + 21, + UNW_VE_V22 = 64 + 22, + UNW_VE_V23 = 64 + 23, + UNW_VE_V24 = 64 + 24, + UNW_VE_V25 = 64 + 25, + UNW_VE_V26 = 64 + 26, + UNW_VE_V27 = 64 + 27, + UNW_VE_V28 = 64 + 28, + UNW_VE_V29 = 64 + 29, + UNW_VE_V30 = 64 + 30, + UNW_VE_V31 = 64 + 31, + UNW_VE_V32 = 64 + 32, + UNW_VE_V33 = 64 + 33, + UNW_VE_V34 = 64 + 34, + UNW_VE_V35 = 64 + 35, + UNW_VE_V36 = 64 + 36, + UNW_VE_V37 = 64 + 37, + UNW_VE_V38 = 64 + 38, + UNW_VE_V39 = 64 + 39, + UNW_VE_V40 = 64 + 40, + UNW_VE_V41 = 64 + 41, + UNW_VE_V42 = 64 + 42, + UNW_VE_V43 = 64 + 43, + UNW_VE_V44 = 64 + 44, + UNW_VE_V45 = 64 + 45, + UNW_VE_V46 = 64 + 46, + UNW_VE_V47 = 64 + 47, + UNW_VE_V48 = 64 + 48, + UNW_VE_V49 = 64 + 49, + UNW_VE_V50 = 64 + 50, + UNW_VE_V51 = 64 + 51, + UNW_VE_V52 = 64 + 52, + UNW_VE_V53 = 64 + 53, + UNW_VE_V54 = 64 + 54, + UNW_VE_V55 = 64 + 55, + UNW_VE_V56 = 64 + 56, + UNW_VE_V57 = 64 + 57, + UNW_VE_V58 = 64 + 58, + UNW_VE_V59 = 64 + 59, + UNW_VE_V60 = 64 + 60, + UNW_VE_V61 = 64 + 61, + UNW_VE_V62 = 64 + 62, + UNW_VE_V63 = 64 + 63, + UNW_VE_VM0 = 128 + 0, + UNW_VE_VM1 = 128 + 1, + UNW_VE_VM2 = 128 + 2, + UNW_VE_VM3 = 128 + 3, + UNW_VE_VM4 = 128 + 4, + UNW_VE_VM5 = 128 + 5, + UNW_VE_VM6 = 128 + 6, + UNW_VE_VM7 = 128 + 7, + UNW_VE_VM8 = 128 + 8, + UNW_VE_VM9 = 128 + 9, + UNW_VE_VM10 = 128 + 10, + UNW_VE_VM11 = 128 + 11, + UNW_VE_VM12 = 128 + 12, + UNW_VE_VM13 = 128 + 13, + UNW_VE_VM14 = 128 + 14, + UNW_VE_VM15 = 128 + 15, // = 143 + + // Following registers don't have DWARF register numbers. + UNW_VE_VIXR = 144, + UNW_VE_VL = 145, +}; + #endif diff --git a/libunwind/src/AddressSpace.hpp b/libunwind/src/AddressSpace.hpp index a4564cb67328..171318ff6370 100644 --- a/libunwind/src/AddressSpace.hpp +++ b/libunwind/src/AddressSpace.hpp @@ -17,6 +17,12 @@ #include <stdlib.h> #include <string.h> +#include "libunwind.h" +#include "config.h" +#include "dwarf2.h" +#include "EHHeaderParser.hpp" +#include "Registers.hpp" + #ifndef _LIBUNWIND_USE_DLADDR #if !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32) #define _LIBUNWIND_USE_DLADDR 1 @@ -40,19 +46,6 @@ struct EHABIIndexEntry { #endif #ifdef __APPLE__ -#include <mach-o/getsect.h> -namespace libunwind { - bool checkKeyMgrRegisteredFDEs(uintptr_t targetAddr, void *&fde); -} -#endif - -#include "libunwind.h" -#include "config.h" -#include "dwarf2.h" -#include "EHHeaderParser.hpp" -#include "Registers.hpp" - -#ifdef __APPLE__ struct dyld_unwind_sections { @@ -62,43 +55,9 @@ namespace libunwind { const void* compact_unwind_section; uintptr_t compact_unwind_section_length; }; - #if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \ - && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) \ - || defined(__IPHONE_OS_VERSION_MIN_REQUIRED) - // In 10.7.0 or later, libSystem.dylib implements this function. - extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *); - #else - // In 10.6.x and earlier, we need to implement this functionality. Note - // that this requires a newer version of libmacho (from cctools) than is - // present in libSystem on 10.6.x (for getsectiondata). - static inline bool _dyld_find_unwind_sections(void* addr, - dyld_unwind_sections* info) { - // Find mach-o image containing address. - Dl_info dlinfo; - if (!dladdr(addr, &dlinfo)) - return false; -#if __LP64__ - const struct mach_header_64 *mh = (const struct mach_header_64 *)dlinfo.dli_fbase; -#else - const struct mach_header *mh = (const struct mach_header *)dlinfo.dli_fbase; -#endif - - // Initialize the return struct - info->mh = (const struct mach_header *)mh; - info->dwarf_section = getsectiondata(mh, "__TEXT", "__eh_frame", &info->dwarf_section_length); - info->compact_unwind_section = getsectiondata(mh, "__TEXT", "__unwind_info", &info->compact_unwind_section_length); - if (!info->dwarf_section) { - info->dwarf_section_length = 0; - } - - if (!info->compact_unwind_section) { - info->compact_unwind_section_length = 0; - } - - return true; - } - #endif + // In 10.7.0 or later, libSystem.dylib implements this function. + extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *); #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL) @@ -139,22 +98,15 @@ extern char __eh_frame_hdr_end; extern char __exidx_start; extern char __exidx_end; -#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) +#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32) -// ELF-based systems may use dl_iterate_phdr() to access sections -// containing unwinding information. The ElfW() macro for pointer-size -// independent ELF header traversal is not provided by <link.h> on some -// systems (e.g., FreeBSD). On these systems the data structures are -// just called Elf_XXX. Define ElfW() locally. -#ifndef _WIN32 -#include <link.h> -#else #include <windows.h> #include <psapi.h> -#endif -#if !defined(ElfW) -#define ElfW(type) Elf_##type -#endif + +#elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) || \ + defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX) + +#include <link.h> #endif @@ -162,11 +114,15 @@ namespace libunwind { /// Used by findUnwindSections() to return info about needed sections. struct UnwindInfoSections { -#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) || \ - defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) - // No dso_base for SEH or ARM EHABI. +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || \ + defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) || \ + defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) + // No dso_base for SEH. uintptr_t dso_base; #endif +#if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) + uintptr_t text_segment_length; +#endif #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) uintptr_t dwarf_section; uintptr_t dwarf_section_length; @@ -290,11 +246,11 @@ inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) { if (p == pend) _LIBUNWIND_ABORT("truncated sleb128 expression"); byte = *p++; - result |= ((byte & 0x7f) << bit); + result |= (uint64_t)(byte & 0x7f) << bit; bit += 7; } while (byte & 0x80); // sign extend negative numbers - if ((byte & 0x40) != 0) + if ((byte & 0x40) != 0 && bit < 64) result |= (-1ULL) << bit; addr = (pint_t) p; return result; @@ -392,23 +348,14 @@ LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, return result; } -#ifdef __APPLE__ -#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL) -#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL) -#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32) -#elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32) -#elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__) -// Code inside findUnwindSections handles all these cases. -// -// Although the above ifdef chain is ugly, there doesn't seem to be a cleaner -// way to handle it. The generalized boolean expression is: -// -// A OR (B AND C) OR (D AND C) OR (B AND E) OR (F AND E) OR (D AND G) -// -// Running it through various boolean expression simplifiers gives expressions -// that don't help at all. -#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) +#if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) +// The ElfW() macro for pointer-size independent ELF header traversal is not +// provided by <link.h> on some systems (e.g., FreeBSD). On these systems the +// data structures are just called Elf_XXX. Define ElfW() locally. +#if !defined(ElfW) + #define ElfW(type) Elf_##type +#endif #if !defined(Elf_Half) typedef ElfW(Half) Elf_Half; #endif @@ -447,15 +394,13 @@ struct _LIBUNWIND_HIDDEN dl_iterate_cb_data { uintptr_t targetAddr; }; -#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) - #if !defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) - #error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform." - #endif - +#if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE) #include "FrameHeaderCache.hpp" -// There should be just one of these per process. -static FrameHeaderCache ProcessFrameHeaderCache; +// Typically there is one cache per process, but when libunwind is built as a +// hermetic static library, then each shared object may have its own cache. +static FrameHeaderCache TheFrameHeaderCache; +#endif static bool checkAddrInSegment(const Elf_Phdr *phdr, size_t image_base, dl_iterate_cb_data *cbdata) { @@ -464,90 +409,93 @@ static bool checkAddrInSegment(const Elf_Phdr *phdr, size_t image_base, uintptr_t end = begin + phdr->p_memsz; if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) { cbdata->sects->dso_base = begin; - cbdata->sects->dwarf_section_length = phdr->p_memsz; + cbdata->sects->text_segment_length = phdr->p_memsz; return true; } } return false; } -int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, size_t pinfo_size, - void *data) { +static bool checkForUnwindInfoSegment(const Elf_Phdr *phdr, size_t image_base, + dl_iterate_cb_data *cbdata) { +#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) + if (phdr->p_type == PT_GNU_EH_FRAME) { + EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo; + uintptr_t eh_frame_hdr_start = image_base + phdr->p_vaddr; + cbdata->sects->dwarf_index_section = eh_frame_hdr_start; + cbdata->sects->dwarf_index_section_length = phdr->p_memsz; + if (EHHeaderParser<LocalAddressSpace>::decodeEHHdr( + *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz, + hdrInfo)) { + // .eh_frame_hdr records the start of .eh_frame, but not its size. + // Rely on a zero terminator to find the end of the section. + cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr; + cbdata->sects->dwarf_section_length = UINTPTR_MAX; + return true; + } + } + return false; +#elif defined(_LIBUNWIND_ARM_EHABI) + if (phdr->p_type == PT_ARM_EXIDX) { + uintptr_t exidx_start = image_base + phdr->p_vaddr; + cbdata->sects->arm_section = exidx_start; + cbdata->sects->arm_section_length = phdr->p_memsz; + return true; + } + return false; +#else +#error Need one of _LIBUNWIND_SUPPORT_DWARF_INDEX or _LIBUNWIND_ARM_EHABI +#endif +} + +static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, + size_t pinfo_size, void *data) { auto cbdata = static_cast<dl_iterate_cb_data *>(data); if (pinfo->dlpi_phnum == 0 || cbdata->targetAddr < pinfo->dlpi_addr) return 0; - if (ProcessFrameHeaderCache.find(pinfo, pinfo_size, data)) +#if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE) + if (TheFrameHeaderCache.find(pinfo, pinfo_size, data)) return 1; +#else + // Avoid warning about unused variable. + (void)pinfo_size; +#endif Elf_Addr image_base = calculateImageBase(pinfo); - bool found_obj = false; - bool found_hdr = false; - // Third phdr is usually the executable phdr. - if (pinfo->dlpi_phnum > 2) - found_obj = checkAddrInSegment(&pinfo->dlpi_phdr[2], image_base, cbdata); + // Most shared objects seen in this callback function likely don't contain the + // target address, so optimize for that. Scan for a matching PT_LOAD segment + // first and bail when it isn't found. + bool found_text = false; + for (Elf_Half i = 0; i < pinfo->dlpi_phnum; ++i) { + if (checkAddrInSegment(&pinfo->dlpi_phdr[i], image_base, cbdata)) { + found_text = true; + break; + } + } + if (!found_text) + return 0; - // PT_GNU_EH_FRAME is usually near the end. Iterate backward. We already know - // that there is one or more phdrs. + // PT_GNU_EH_FRAME and PT_ARM_EXIDX are usually near the end. Iterate + // backward. + bool found_unwind = false; for (Elf_Half i = pinfo->dlpi_phnum; i > 0; i--) { const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i - 1]; - if (!found_hdr && phdr->p_type == PT_GNU_EH_FRAME) { - EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo; - uintptr_t eh_frame_hdr_start = image_base + phdr->p_vaddr; - cbdata->sects->dwarf_index_section = eh_frame_hdr_start; - cbdata->sects->dwarf_index_section_length = phdr->p_memsz; - found_hdr = EHHeaderParser<LocalAddressSpace>::decodeEHHdr( - *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz, - hdrInfo); - if (found_hdr) - cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr; - } else if (!found_obj) { - found_obj = checkAddrInSegment(phdr, image_base, cbdata); - } - if (found_obj && found_hdr) { - ProcessFrameHeaderCache.add(cbdata->sects); - return 1; + if (checkForUnwindInfoSegment(phdr, image_base, cbdata)) { + found_unwind = true; + break; } } - cbdata->sects->dwarf_section_length = 0; - return 0; -} - -#else // defined(LIBUNWIND_SUPPORT_DWARF_UNWIND) -// Given all the #ifdef's above, the code here is for -// defined(LIBUNWIND_ARM_EHABI) - -int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, size_t, void *data) { - auto *cbdata = static_cast<dl_iterate_cb_data *>(data); - bool found_obj = false; - bool found_hdr = false; - - assert(cbdata); - assert(cbdata->sects); - - if (cbdata->targetAddr < pinfo->dlpi_addr) + if (!found_unwind) return 0; - Elf_Addr image_base = calculateImageBase(pinfo); - - 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 = image_base + phdr->p_vaddr; - uintptr_t end = begin + phdr->p_memsz; - if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) - found_obj = true; - } else if (phdr->p_type == PT_ARM_EXIDX) { - uintptr_t exidx_start = image_base + phdr->p_vaddr; - cbdata->sects->arm_section = exidx_start; - cbdata->sects->arm_section_length = phdr->p_memsz; - found_hdr = true; - } - } - return found_obj && found_hdr; +#if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE) + TheFrameHeaderCache.add(cbdata->sects); +#endif + return 1; } -#endif // defined(LIBUNWIND_SUPPORT_DWARF_UNWIND) -#endif // defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + +#endif // defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, @@ -565,6 +513,7 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, return true; } #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL) + info.dso_base = 0; // Bare metal is statically linked, so no need to ask the dynamic loader info.dwarf_section_length = (uintptr_t)(&__eh_frame_end - &__eh_frame_start); info.dwarf_section = (uintptr_t)(&__eh_frame_start); @@ -631,16 +580,14 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, (void)targetAddr; (void)info; return true; -#elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__) - // For ARM EHABI, Bionic didn't implement dl_iterate_phdr until API 21. After - // API 21, dl_iterate_phdr exists, but dl_unwind_find_exidx is much faster. +#elif defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX) int length = 0; info.arm_section = (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length); info.arm_section_length = (uintptr_t)length * sizeof(EHABIIndexEntry); if (info.arm_section && info.arm_section_length) return true; -#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) +#elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) dl_iterate_cb_data cb_data = {this, &info, targetAddr}; int found = dl_iterate_phdr(findUnwindSectionsByPhdr, &cb_data); return static_cast<bool>(found); @@ -651,14 +598,10 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, 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, diff --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp index ee98f538d437..c39cabe1f783 100644 --- a/libunwind/src/DwarfInstructions.hpp +++ b/libunwind/src/DwarfInstructions.hpp @@ -93,7 +93,8 @@ typename A::pint_t DwarfInstructions<A, R>::getSavedRegister( case CFI_Parser<A>::kRegisterInRegister: return registers.getRegister((int)savedReg.value); - + case CFI_Parser<A>::kRegisterUndefined: + return 0; case CFI_Parser<A>::kRegisterUnused: case CFI_Parser<A>::kRegisterOffsetFromCFA: // FIX ME @@ -117,6 +118,7 @@ double DwarfInstructions<A, R>::getSavedFloatRegister( case CFI_Parser<A>::kRegisterIsExpression: case CFI_Parser<A>::kRegisterUnused: + case CFI_Parser<A>::kRegisterUndefined: case CFI_Parser<A>::kRegisterOffsetFromCFA: case CFI_Parser<A>::kRegisterInRegister: // FIX ME @@ -140,6 +142,7 @@ v128 DwarfInstructions<A, R>::getSavedVectorRegister( case CFI_Parser<A>::kRegisterIsExpression: case CFI_Parser<A>::kRegisterUnused: + case CFI_Parser<A>::kRegisterUndefined: case CFI_Parser<A>::kRegisterOffsetFromCFA: case CFI_Parser<A>::kRegisterInRegister: // FIX ME @@ -190,6 +193,10 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc, prolog.savedRegisters[i])); else return UNW_EBADREG; + } else if (i == (int)cieInfo.returnAddressRegister) { + // Leaf function keeps the return address in register and there is no + // explicit intructions how to restore it. + returnAddress = registers.getRegister(cieInfo.returnAddressRegister); } } diff --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp index d05ac468367f..de0eb6de9d70 100644 --- a/libunwind/src/DwarfParser.hpp +++ b/libunwind/src/DwarfParser.hpp @@ -69,6 +69,7 @@ public: }; enum RegisterSavedWhere { kRegisterUnused, + kRegisterUndefined, kRegisterInCFA, kRegisterOffsetFromCFA, kRegisterInRegister, @@ -87,9 +88,6 @@ public: int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset int64_t cfaExpression; // CFA = expression uint32_t spExtraArgSize; - uint32_t codeOffsetAtStackDecrement; - bool registersInOtherRegisters; - bool sameValueUsed; RegisterLocation savedRegisters[kMaxRegisterNumber + 1]; enum class InitializeTime { kLazy, kNormal }; @@ -134,8 +132,26 @@ public: PrologInfo info; }; + struct RememberStack { + PrologInfoStackEntry *entry; + RememberStack() : entry(nullptr) {} + ~RememberStack() { +#if defined(_LIBUNWIND_REMEMBER_CLEANUP_NEEDED) + // Clean up rememberStack. Even in the case where every + // DW_CFA_remember_state is paired with a DW_CFA_restore_state, + // parseInstructions can skip restore opcodes if it reaches the target PC + // and stops interpreting, so we have to make sure we don't leak memory. + while (entry) { + PrologInfoStackEntry *next = entry->next; + _LIBUNWIND_REMEMBER_FREE(entry); + entry = next; + } +#endif + } + }; + static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, - uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo, + uintptr_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo, CIE_Info *cieInfo); static const char *decodeFDE(A &addressSpace, pint_t fdeStart, FDE_Info *fdeInfo, CIE_Info *cieInfo); @@ -144,13 +160,6 @@ public: int arch, PrologInfo *results); static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo); - -private: - static bool parseInstructions(A &addressSpace, pint_t instructions, - pint_t instructionsEnd, const CIE_Info &cieInfo, - pint_t pcoffset, - PrologInfoStackEntry *&rememberStack, int arch, - PrologInfo *results); }; /// Parse a FDE into a CIE_Info and an FDE_Info @@ -166,7 +175,7 @@ const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart, p += 8; } if (cfiLength == 0) - return "FDE has zero length"; // end marker + return "FDE has zero length"; // zero terminator uint32_t ciePointer = addressSpace.get32(p); if (ciePointer == 0) return "FDE is really a CIE"; // this is a CIE not an FDE @@ -211,11 +220,13 @@ const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart, /// Scan an eh_frame section to find an FDE for a pc template <typename A> bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, - uint32_t sectionLength, pint_t fdeHint, + uintptr_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo, CIE_Info *cieInfo) { //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc); pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart; - const pint_t ehSectionEnd = p + sectionLength; + const pint_t ehSectionEnd = (sectionLength == UINTPTR_MAX) + ? static_cast<pint_t>(-1) + : (ehSectionStart + sectionLength); while (p < ehSectionEnd) { pint_t currentCFI = p; //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p); @@ -227,7 +238,7 @@ bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, p += 8; } if (cfiLength == 0) - return false; // end marker + return false; // zero terminator uint32_t id = addressSpace.get32(p); if (id == 0) { // Skip over CIEs. @@ -336,7 +347,8 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie, // parse data alignment factor cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd); // parse return address register - uint64_t raReg = addressSpace.getULEB128(p, cieContentEnd); + uint64_t raReg = (version == 1) ? addressSpace.get8(p++) + : addressSpace.getULEB128(p, cieContentEnd); assert(raReg < 255 && "return address register too large"); cieInfo->returnAddressRegister = (uint8_t)raReg; // parse augmentation data based on augmentation string @@ -390,418 +402,409 @@ bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo, const CIE_Info &cieInfo, pint_t upToPC, int arch, PrologInfo *results) { - PrologInfoStackEntry *rememberStack = NULL; - - // parse CIE then FDE instructions - bool returnValue = - parseInstructions(addressSpace, cieInfo.cieInstructions, - cieInfo.cieStart + cieInfo.cieLength, cieInfo, - (pint_t)(-1), rememberStack, arch, results) && - parseInstructions(addressSpace, fdeInfo.fdeInstructions, - fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo, - upToPC - fdeInfo.pcStart, rememberStack, arch, results); - -#if !defined(_LIBUNWIND_NO_HEAP) - // Clean up rememberStack. Even in the case where every DW_CFA_remember_state - // is paired with a DW_CFA_restore_state, parseInstructions can skip restore - // opcodes if it reaches the target PC and stops interpreting, so we have to - // make sure we don't leak memory. - while (rememberStack) { - PrologInfoStackEntry *next = rememberStack->next; - free(rememberStack); - rememberStack = next; - } -#endif - - return returnValue; -} + // Alloca is used for the allocation of the rememberStack entries. It removes + // the dependency on new/malloc but the below for loop can not be refactored + // into functions. Entry could be saved during the processing of a CIE and + // restored by an FDE. + RememberStack rememberStack; + + struct ParseInfo { + pint_t instructions; + pint_t instructionsEnd; + pint_t pcoffset; + }; -/// "run" the DWARF instructions -template <typename A> -bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions, - pint_t instructionsEnd, - const CIE_Info &cieInfo, pint_t pcoffset, - PrologInfoStackEntry *&rememberStack, - int arch, PrologInfo *results) { - pint_t p = instructions; - pint_t codeOffset = 0; - // initialState initialized as registers in results are modified. Use - // PrologInfo accessor functions to avoid reading uninitialized data. - PrologInfo initialState(PrologInfo::InitializeTime::kLazy); - - _LIBUNWIND_TRACE_DWARF("parseInstructions(instructions=0x%0" PRIx64 ")\n", - static_cast<uint64_t>(instructionsEnd)); - - // see DWARF Spec, section 6.4.2 for details on unwind opcodes - while ((p < instructionsEnd) && (codeOffset < pcoffset)) { - uint64_t reg; - uint64_t reg2; - int64_t offset; - uint64_t length; - uint8_t opcode = addressSpace.get8(p); - uint8_t operand; -#if !defined(_LIBUNWIND_NO_HEAP) - PrologInfoStackEntry *entry; -#endif - ++p; - switch (opcode) { - case DW_CFA_nop: - _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n"); - break; - case DW_CFA_set_loc: - codeOffset = - addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding); - _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n"); - break; - case DW_CFA_advance_loc1: - codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor); - p += 1; - _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n", - static_cast<uint64_t>(codeOffset)); - break; - case DW_CFA_advance_loc2: - codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor); - p += 2; - _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n", - static_cast<uint64_t>(codeOffset)); - break; - case DW_CFA_advance_loc4: - codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor); - p += 4; - _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n", - static_cast<uint64_t>(codeOffset)); - break; - case DW_CFA_offset_extended: - reg = addressSpace.getULEB128(p, instructionsEnd); - offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) - * cieInfo.dataAlignFactor; - if (reg > kMaxRegisterNumber) { - _LIBUNWIND_LOG0( - "malformed DW_CFA_offset_extended DWARF unwind, reg too big"); - return false; - } - results->setRegister(reg, kRegisterInCFA, offset, initialState); - _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", " - "offset=%" PRId64 ")\n", - reg, offset); - break; - case DW_CFA_restore_extended: - reg = addressSpace.getULEB128(p, instructionsEnd); - if (reg > kMaxRegisterNumber) { - _LIBUNWIND_LOG0( - "malformed DW_CFA_restore_extended DWARF unwind, reg too big"); - return false; - } - results->restoreRegisterToInitialState(reg, initialState); - _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg); - break; - case DW_CFA_undefined: - reg = addressSpace.getULEB128(p, instructionsEnd); - if (reg > kMaxRegisterNumber) { - _LIBUNWIND_LOG0( - "malformed DW_CFA_undefined DWARF unwind, reg too big"); - return false; - } - results->setRegisterLocation(reg, kRegisterUnused, initialState); - _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg); - break; - case DW_CFA_same_value: - reg = addressSpace.getULEB128(p, instructionsEnd); - if (reg > kMaxRegisterNumber) { - _LIBUNWIND_LOG0( - "malformed DW_CFA_same_value DWARF unwind, reg too big"); - return false; - } - // <rdar://problem/8456377> DW_CFA_same_value unsupported - // "same value" means register was stored in frame, but its current - // value has not changed, so no need to restore from frame. - // We model this as if the register was never saved. - results->setRegisterLocation(reg, kRegisterUnused, initialState); - // set flag to disable conversion to compact unwind - results->sameValueUsed = true; - _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg); - break; - case DW_CFA_register: - reg = addressSpace.getULEB128(p, instructionsEnd); - reg2 = addressSpace.getULEB128(p, instructionsEnd); - if (reg > kMaxRegisterNumber) { - _LIBUNWIND_LOG0( - "malformed DW_CFA_register DWARF unwind, reg too big"); - return false; - } - if (reg2 > kMaxRegisterNumber) { - _LIBUNWIND_LOG0( - "malformed DW_CFA_register DWARF unwind, reg2 too big"); - return false; - } - results->setRegister(reg, kRegisterInRegister, (int64_t)reg2, - initialState); - // set flag to disable conversion to compact unwind - results->registersInOtherRegisters = true; - _LIBUNWIND_TRACE_DWARF( - "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2); - break; -#if !defined(_LIBUNWIND_NO_HEAP) - case DW_CFA_remember_state: - // avoid operator new, because that would be an upward dependency - entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry)); - if (entry != NULL) { - entry->next = rememberStack; - entry->info = *results; - rememberStack = entry; - } else { - return false; - } - _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n"); - break; - case DW_CFA_restore_state: - if (rememberStack != NULL) { - PrologInfoStackEntry *top = rememberStack; - *results = top->info; - rememberStack = top->next; - free((char *)top); - } else { - return false; - } - _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n"); - break; -#endif - case DW_CFA_def_cfa: - reg = addressSpace.getULEB128(p, instructionsEnd); - offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd); - if (reg > kMaxRegisterNumber) { - _LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big"); - return false; - } - results->cfaRegister = (uint32_t)reg; - results->cfaRegisterOffset = (int32_t)offset; - _LIBUNWIND_TRACE_DWARF( - "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", reg, offset); - break; - case DW_CFA_def_cfa_register: - reg = addressSpace.getULEB128(p, instructionsEnd); - if (reg > kMaxRegisterNumber) { - _LIBUNWIND_LOG0( - "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big"); - return false; - } - results->cfaRegister = (uint32_t)reg; - _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg); - break; - case DW_CFA_def_cfa_offset: - results->cfaRegisterOffset = (int32_t) - addressSpace.getULEB128(p, instructionsEnd); - results->codeOffsetAtStackDecrement = (uint32_t)codeOffset; - _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n", - results->cfaRegisterOffset); - break; - case DW_CFA_def_cfa_expression: - results->cfaRegister = 0; - results->cfaExpression = (int64_t)p; - length = addressSpace.getULEB128(p, instructionsEnd); - assert(length < static_cast<pint_t>(~0) && "pointer overflow"); - p += static_cast<pint_t>(length); - _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64 - ", length=%" PRIu64 ")\n", - results->cfaExpression, length); - break; - case DW_CFA_expression: - reg = addressSpace.getULEB128(p, instructionsEnd); - if (reg > kMaxRegisterNumber) { - _LIBUNWIND_LOG0( - "malformed DW_CFA_expression DWARF unwind, reg too big"); - return false; - } - results->setRegister(reg, kRegisterAtExpression, (int64_t)p, - initialState); - length = addressSpace.getULEB128(p, instructionsEnd); - assert(length < static_cast<pint_t>(~0) && "pointer overflow"); - p += static_cast<pint_t>(length); - _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", " - "expression=0x%" PRIx64 ", " - "length=%" PRIu64 ")\n", - reg, results->savedRegisters[reg].value, length); - break; - case DW_CFA_offset_extended_sf: - reg = addressSpace.getULEB128(p, instructionsEnd); - if (reg > kMaxRegisterNumber) { - _LIBUNWIND_LOG0( - "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big"); - return false; - } - offset = - addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; - results->setRegister(reg, kRegisterInCFA, offset, initialState); - _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", " - "offset=%" PRId64 ")\n", - reg, offset); - break; - case DW_CFA_def_cfa_sf: - reg = addressSpace.getULEB128(p, instructionsEnd); - offset = - addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; - if (reg > kMaxRegisterNumber) { - _LIBUNWIND_LOG0( - "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big"); - return false; - } - results->cfaRegister = (uint32_t)reg; - results->cfaRegisterOffset = (int32_t)offset; - _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", " - "offset=%" PRId64 ")\n", - reg, offset); - break; - case DW_CFA_def_cfa_offset_sf: - results->cfaRegisterOffset = (int32_t) - (addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor); - results->codeOffsetAtStackDecrement = (uint32_t)codeOffset; - _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n", - results->cfaRegisterOffset); - break; - case DW_CFA_val_offset: - reg = addressSpace.getULEB128(p, instructionsEnd); - if (reg > kMaxRegisterNumber) { - _LIBUNWIND_LOG( - "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64 - ") out of range\n", - reg); - return false; - } - offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) - * cieInfo.dataAlignFactor; - results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState); - _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", " - "offset=%" PRId64 "\n", - reg, offset); - break; - case DW_CFA_val_offset_sf: - reg = addressSpace.getULEB128(p, instructionsEnd); - if (reg > kMaxRegisterNumber) { - _LIBUNWIND_LOG0( - "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big"); - return false; - } - offset = - addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; - results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState); - _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", " - "offset=%" PRId64 "\n", - reg, offset); - break; - case DW_CFA_val_expression: - reg = addressSpace.getULEB128(p, instructionsEnd); - if (reg > kMaxRegisterNumber) { - _LIBUNWIND_LOG0( - "malformed DW_CFA_val_expression DWARF unwind, reg too big"); - return false; - } - results->setRegister(reg, kRegisterIsExpression, (int64_t)p, - initialState); - length = addressSpace.getULEB128(p, instructionsEnd); - assert(length < static_cast<pint_t>(~0) && "pointer overflow"); - p += static_cast<pint_t>(length); - _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", " - "expression=0x%" PRIx64 ", length=%" PRIu64 ")\n", - reg, results->savedRegisters[reg].value, length); - break; - case DW_CFA_GNU_args_size: - length = addressSpace.getULEB128(p, instructionsEnd); - results->spExtraArgSize = (uint32_t)length; - _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length); - break; - case DW_CFA_GNU_negative_offset_extended: - reg = addressSpace.getULEB128(p, instructionsEnd); - if (reg > kMaxRegisterNumber) { - _LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF " - "unwind, reg too big"); - return false; + ParseInfo parseInfoArray[] = { + {cieInfo.cieInstructions, cieInfo.cieStart + cieInfo.cieLength, + (pint_t)(-1)}, + {fdeInfo.fdeInstructions, fdeInfo.fdeStart + fdeInfo.fdeLength, + upToPC - fdeInfo.pcStart}}; + + for (const auto &info : parseInfoArray) { + pint_t p = info.instructions; + pint_t instructionsEnd = info.instructionsEnd; + pint_t pcoffset = info.pcoffset; + pint_t codeOffset = 0; + + // initialState initialized as registers in results are modified. Use + // PrologInfo accessor functions to avoid reading uninitialized data. + PrologInfo initialState(PrologInfo::InitializeTime::kLazy); + + _LIBUNWIND_TRACE_DWARF("parseFDEInstructions(instructions=0x%0" PRIx64 + ")\n", + static_cast<uint64_t>(instructionsEnd)); + + // see DWARF Spec, section 6.4.2 for details on unwind opcodes + while ((p < instructionsEnd) && (codeOffset < pcoffset)) { + uint64_t reg; + uint64_t reg2; + int64_t offset; + uint64_t length; + uint8_t opcode = addressSpace.get8(p); + uint8_t operand; + + ++p; + switch (opcode) { + case DW_CFA_nop: + _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n"); + break; + case DW_CFA_set_loc: + codeOffset = addressSpace.getEncodedP(p, instructionsEnd, + cieInfo.pointerEncoding); + _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n"); + break; + case DW_CFA_advance_loc1: + codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor); + p += 1; + _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n", + static_cast<uint64_t>(codeOffset)); + break; + case DW_CFA_advance_loc2: + codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor); + p += 2; + _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n", + static_cast<uint64_t>(codeOffset)); + break; + case DW_CFA_advance_loc4: + codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor); + p += 4; + _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n", + static_cast<uint64_t>(codeOffset)); + break; + case DW_CFA_offset_extended: + reg = addressSpace.getULEB128(p, instructionsEnd); + offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) * + cieInfo.dataAlignFactor; + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_offset_extended DWARF unwind, reg too big"); + return false; + } + results->setRegister(reg, kRegisterInCFA, offset, initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", " + "offset=%" PRId64 ")\n", + reg, offset); + break; + case DW_CFA_restore_extended: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_restore_extended DWARF unwind, reg too big"); + return false; + } + results->restoreRegisterToInitialState(reg, initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n", + reg); + break; + case DW_CFA_undefined: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_undefined DWARF unwind, reg too big"); + return false; + } + results->setRegisterLocation(reg, kRegisterUndefined, initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg); + break; + case DW_CFA_same_value: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_same_value DWARF unwind, reg too big"); + return false; + } + // <rdar://problem/8456377> DW_CFA_same_value unsupported + // "same value" means register was stored in frame, but its current + // value has not changed, so no need to restore from frame. + // We model this as if the register was never saved. + results->setRegisterLocation(reg, kRegisterUnused, initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg); + break; + case DW_CFA_register: + reg = addressSpace.getULEB128(p, instructionsEnd); + reg2 = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_register DWARF unwind, reg too big"); + return false; + } + if (reg2 > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_register DWARF unwind, reg2 too big"); + return false; + } + results->setRegister(reg, kRegisterInRegister, (int64_t)reg2, + initialState); + _LIBUNWIND_TRACE_DWARF( + "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2); + break; + case DW_CFA_remember_state: { + // Avoid operator new because that would be an upward dependency. + // Avoid malloc because it needs heap allocation. + PrologInfoStackEntry *entry = + (PrologInfoStackEntry *)_LIBUNWIND_REMEMBER_ALLOC( + sizeof(PrologInfoStackEntry)); + if (entry != NULL) { + entry->next = rememberStack.entry; + entry->info = *results; + rememberStack.entry = entry; + } else { + return false; + } + _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n"); + break; } - offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) - * cieInfo.dataAlignFactor; - results->setRegister(reg, kRegisterInCFA, -offset, initialState); - _LIBUNWIND_TRACE_DWARF( - "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset); - break; + case DW_CFA_restore_state: + if (rememberStack.entry != NULL) { + PrologInfoStackEntry *top = rememberStack.entry; + *results = top->info; + rememberStack.entry = top->next; + _LIBUNWIND_REMEMBER_FREE(top); + } else { + return false; + } + _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n"); + break; + case DW_CFA_def_cfa: + reg = addressSpace.getULEB128(p, instructionsEnd); + offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big"); + return false; + } + results->cfaRegister = (uint32_t)reg; + results->cfaRegisterOffset = (int32_t)offset; + _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 + ")\n", + reg, offset); + break; + case DW_CFA_def_cfa_register: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big"); + return false; + } + results->cfaRegister = (uint32_t)reg; + _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg); + break; + case DW_CFA_def_cfa_offset: + results->cfaRegisterOffset = + (int32_t)addressSpace.getULEB128(p, instructionsEnd); + _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n", + results->cfaRegisterOffset); + break; + case DW_CFA_def_cfa_expression: + results->cfaRegister = 0; + results->cfaExpression = (int64_t)p; + length = addressSpace.getULEB128(p, instructionsEnd); + assert(length < static_cast<pint_t>(~0) && "pointer overflow"); + p += static_cast<pint_t>(length); + _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64 + ", length=%" PRIu64 ")\n", + results->cfaExpression, length); + break; + case DW_CFA_expression: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_expression DWARF unwind, reg too big"); + return false; + } + results->setRegister(reg, kRegisterAtExpression, (int64_t)p, + initialState); + length = addressSpace.getULEB128(p, instructionsEnd); + assert(length < static_cast<pint_t>(~0) && "pointer overflow"); + p += static_cast<pint_t>(length); + _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", " + "expression=0x%" PRIx64 ", " + "length=%" PRIu64 ")\n", + reg, results->savedRegisters[reg].value, length); + break; + case DW_CFA_offset_extended_sf: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big"); + return false; + } + offset = addressSpace.getSLEB128(p, instructionsEnd) * + cieInfo.dataAlignFactor; + results->setRegister(reg, kRegisterInCFA, offset, initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", " + "offset=%" PRId64 ")\n", + reg, offset); + break; + case DW_CFA_def_cfa_sf: + reg = addressSpace.getULEB128(p, instructionsEnd); + offset = addressSpace.getSLEB128(p, instructionsEnd) * + cieInfo.dataAlignFactor; + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big"); + return false; + } + results->cfaRegister = (uint32_t)reg; + results->cfaRegisterOffset = (int32_t)offset; + _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", " + "offset=%" PRId64 ")\n", + reg, offset); + break; + case DW_CFA_def_cfa_offset_sf: + results->cfaRegisterOffset = + (int32_t)(addressSpace.getSLEB128(p, instructionsEnd) * + cieInfo.dataAlignFactor); + _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n", + results->cfaRegisterOffset); + break; + case DW_CFA_val_offset: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG( + "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64 + ") out of range\n", + reg); + return false; + } + offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) * + cieInfo.dataAlignFactor; + results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", " + "offset=%" PRId64 "\n", + reg, offset); + break; + case DW_CFA_val_offset_sf: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big"); + return false; + } + offset = addressSpace.getSLEB128(p, instructionsEnd) * + cieInfo.dataAlignFactor; + results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", " + "offset=%" PRId64 "\n", + reg, offset); + break; + case DW_CFA_val_expression: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_val_expression DWARF unwind, reg too big"); + return false; + } + results->setRegister(reg, kRegisterIsExpression, (int64_t)p, + initialState); + length = addressSpace.getULEB128(p, instructionsEnd); + assert(length < static_cast<pint_t>(~0) && "pointer overflow"); + p += static_cast<pint_t>(length); + _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", " + "expression=0x%" PRIx64 ", length=%" PRIu64 + ")\n", + reg, results->savedRegisters[reg].value, length); + break; + case DW_CFA_GNU_args_size: + length = addressSpace.getULEB128(p, instructionsEnd); + results->spExtraArgSize = (uint32_t)length; + _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length); + break; + case DW_CFA_GNU_negative_offset_extended: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF " + "unwind, reg too big"); + return false; + } + offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) * + cieInfo.dataAlignFactor; + results->setRegister(reg, kRegisterInCFA, -offset, initialState); + _LIBUNWIND_TRACE_DWARF( + "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset); + break; #if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC) - // The same constant is used to represent different instructions on - // AArch64 (negate_ra_state) and SPARC (window_save). - static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save, - "uses the same constant"); - case DW_CFA_AARCH64_negate_ra_state: - switch (arch) { + // The same constant is used to represent different instructions on + // AArch64 (negate_ra_state) and SPARC (window_save). + static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save, + "uses the same constant"); + case DW_CFA_AARCH64_negate_ra_state: + switch (arch) { #if defined(_LIBUNWIND_TARGET_AARCH64) case REGISTERS_ARM64: { int64_t value = results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^ 0x1; - results->setRegisterValue(UNW_ARM64_RA_SIGN_STATE, value, initialState); + results->setRegisterValue(UNW_ARM64_RA_SIGN_STATE, value, + initialState); _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n"); } break; #endif #if defined(_LIBUNWIND_TARGET_SPARC) - // case DW_CFA_GNU_window_save: - case REGISTERS_SPARC: - _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n"); - for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) { - results->setRegister(reg, kRegisterInRegister, - ((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0, - initialState); - } + // case DW_CFA_GNU_window_save: + case REGISTERS_SPARC: + _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n"); + for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) { + results->setRegister(reg, kRegisterInRegister, + ((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0, + initialState); + } - for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) { - results->setRegister(reg, kRegisterInCFA, - ((int64_t)reg - UNW_SPARC_L0) * 4, initialState); + for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) { + results->setRegister(reg, kRegisterInCFA, + ((int64_t)reg - UNW_SPARC_L0) * 4, + initialState); + } + break; +#endif } break; -#endif - } - break; #else - (void)arch; + (void)arch; #endif - default: - operand = opcode & 0x3F; - switch (opcode & 0xC0) { - case DW_CFA_offset: - reg = operand; - if (reg > kMaxRegisterNumber) { - _LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64 - ") out of range", - reg); - return false; - } - offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) - * cieInfo.dataAlignFactor; - results->setRegister(reg, kRegisterInCFA, offset, initialState); - _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n", - operand, offset); - break; - case DW_CFA_advance_loc: - codeOffset += operand * cieInfo.codeAlignFactor; - _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n", - static_cast<uint64_t>(codeOffset)); - break; - case DW_CFA_restore: - reg = operand; - if (reg > kMaxRegisterNumber) { - _LIBUNWIND_LOG("malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64 - ") out of range", - reg); + default: + operand = opcode & 0x3F; + switch (opcode & 0xC0) { + case DW_CFA_offset: + reg = operand; + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64 + ") out of range", + reg); + return false; + } + offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) * + cieInfo.dataAlignFactor; + results->setRegister(reg, kRegisterInCFA, offset, initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n", + operand, offset); + break; + case DW_CFA_advance_loc: + codeOffset += operand * cieInfo.codeAlignFactor; + _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n", + static_cast<uint64_t>(codeOffset)); + break; + case DW_CFA_restore: + reg = operand; + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG( + "malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64 + ") out of range", + reg); + return false; + } + results->restoreRegisterToInitialState(reg, initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n", + static_cast<uint64_t>(operand)); + break; + default: + _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode); return false; } - results->restoreRegisterToInitialState(reg, initialState); - _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n", - static_cast<uint64_t>(operand)); - break; - default: - _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode); - return false; } } } - return true; } diff --git a/libunwind/src/FrameHeaderCache.hpp b/libunwind/src/FrameHeaderCache.hpp index 813fcd408b26..54d5d33c3cd7 100644 --- a/libunwind/src/FrameHeaderCache.hpp +++ b/libunwind/src/FrameHeaderCache.hpp @@ -32,7 +32,7 @@ class _LIBUNWIND_HIDDEN FrameHeaderCache { struct CacheEntry { uintptr_t LowPC() { return Info.dso_base; }; - uintptr_t HighPC() { return Info.dso_base + Info.dwarf_section_length; }; + uintptr_t HighPC() { return Info.dso_base + Info.text_segment_length; }; UnwindInfoSections Info; CacheEntry *Next; }; diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp index c76b05bf314e..efeaf435591e 100644 --- a/libunwind/src/Registers.hpp +++ b/libunwind/src/Registers.hpp @@ -36,9 +36,12 @@ enum { REGISTERS_SPARC, REGISTERS_HEXAGON, REGISTERS_RISCV, + REGISTERS_VE, }; #if defined(_LIBUNWIND_TARGET_I386) +class _LIBUNWIND_HIDDEN Registers_x86; +extern "C" void __libunwind_Registers_x86_jumpto(Registers_x86 *); /// Registers_x86 holds the register state of a thread in a 32-bit intel /// process. class _LIBUNWIND_HIDDEN Registers_x86 { @@ -56,7 +59,7 @@ public: v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); static const char *getRegisterName(int num); - void jumpto(); + void jumpto() { __libunwind_Registers_x86_jumpto(this); } static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86; } static int getArch() { return REGISTERS_X86; } @@ -248,6 +251,8 @@ inline void Registers_x86::setVectorRegister(int, v128) { #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; +extern "C" void __libunwind_Registers_x86_64_jumpto(Registers_x86_64 *); class _LIBUNWIND_HIDDEN Registers_x86_64 { public: Registers_x86_64(); @@ -263,7 +268,7 @@ public: v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); static const char *getRegisterName(int num); - void jumpto(); + void jumpto() { __libunwind_Registers_x86_64_jumpto(this); } static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64; } static int getArch() { return REGISTERS_X86_64; } @@ -1510,12 +1515,12 @@ inline void Registers_ppc64::setFloatRegister(int regNum, double value) { } inline bool Registers_ppc64::validVectorRegister(int regNum) const { -#ifdef PPC64_HAS_VMX +#if defined(__VSX__) if (regNum >= UNW_PPC64_VS0 && regNum <= UNW_PPC64_VS31) return true; if (regNum >= UNW_PPC64_VS32 && regNum <= UNW_PPC64_VS63) return true; -#else +#elif defined(__ALTIVEC__) if (regNum >= UNW_PPC64_V0 && regNum <= UNW_PPC64_V31) return true; #endif @@ -1771,6 +1776,8 @@ inline const char *Registers_ppc64::getRegisterName(int regNum) { #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; +extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *); class _LIBUNWIND_HIDDEN Registers_arm64 { public: Registers_arm64(); @@ -1786,7 +1793,7 @@ public: v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); static const char *getRegisterName(int num); - void jumpto(); + void jumpto() { __libunwind_Registers_arm64_jumpto(this); } static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64; } static int getArch() { return REGISTERS_ARM64; } @@ -3977,6 +3984,447 @@ inline void Registers_riscv::setVectorRegister(int, v128) { _LIBUNWIND_ABORT("no riscv vector register support yet"); } #endif // _LIBUNWIND_TARGET_RISCV + +#if defined(_LIBUNWIND_TARGET_VE) +/// Registers_ve holds the register state of a thread in a VE process. +class _LIBUNWIND_HIDDEN Registers_ve { +public: + Registers_ve(); + Registers_ve(const void *registers); + + bool validRegister(int num) const; + uint64_t getRegister(int num) const; + void setRegister(int num, uint64_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto(); + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_VE; } + static int getArch() { return REGISTERS_VE; } + + uint64_t getSP() const { return _registers.__s[11]; } + void setSP(uint64_t value) { _registers.__s[11] = value; } + uint64_t getIP() const { return _registers.__ic; } + void setIP(uint64_t value) { _registers.__ic = value; } + +private: + // FIXME: Need to store not only scalar registers but also vector and vector + // mask registers. VEOS uses mcontext_t defined in ucontext.h. It takes + // 524288 bytes (65536*8 bytes), though. Currently, we use libunwind for + // SjLj exception support only, so Registers_ve is not implemented completely. + struct ve_thread_state_t { + uint64_t __s[64]; // s0-s64 + uint64_t __ic; // Instruction counter (IC) + uint64_t __vixr; // Vector Index Register + uint64_t __vl; // Vector Length Register + }; + + ve_thread_state_t _registers; // total 67 registers + + // Currently no vector register is preserved. +}; + +inline Registers_ve::Registers_ve(const void *registers) { + static_assert((check_fit<Registers_ve, unw_context_t>::does_fit), + "ve registers do not fit into unw_context_t"); + memcpy(&_registers, static_cast<const uint8_t *>(registers), + sizeof(_registers)); + static_assert(sizeof(_registers) == 536, + "expected vector register offset to be 536"); +} + +inline Registers_ve::Registers_ve() { + memset(&_registers, 0, sizeof(_registers)); +} + +inline bool Registers_ve::validRegister(int regNum) const { + if (regNum >= UNW_VE_S0 && regNum <= UNW_VE_S63) + return true; + + switch (regNum) { + case UNW_REG_IP: + case UNW_REG_SP: + case UNW_VE_VIXR: + case UNW_VE_VL: + return true; + default: + return false; + } +} + +inline uint64_t Registers_ve::getRegister(int regNum) const { + if (regNum >= UNW_VE_S0 && regNum <= UNW_VE_S63) + return _registers.__s[regNum - UNW_VE_S0]; + + switch (regNum) { + case UNW_REG_IP: + return _registers.__ic; + case UNW_REG_SP: + return _registers.__s[11]; + case UNW_VE_VIXR: + return _registers.__vixr; + case UNW_VE_VL: + return _registers.__vl; + } + _LIBUNWIND_ABORT("unsupported ve register"); +} + +inline void Registers_ve::setRegister(int regNum, uint64_t value) { + if (regNum >= UNW_VE_S0 && regNum <= UNW_VE_S63) { + _registers.__s[regNum - UNW_VE_S0] = value; + return; + } + + switch (regNum) { + case UNW_REG_IP: + _registers.__ic = value; + return; + case UNW_REG_SP: + _registers.__s[11] = value; + return; + case UNW_VE_VIXR: + _registers.__vixr = value; + return; + case UNW_VE_VL: + _registers.__vl = value; + return; + } + _LIBUNWIND_ABORT("unsupported ve register"); +} + +inline bool Registers_ve::validFloatRegister(int /* regNum */) const { + return false; +} + +inline double Registers_ve::getFloatRegister(int /* regNum */) const { + _LIBUNWIND_ABORT("VE doesn't have float registers"); +} + +inline void Registers_ve::setFloatRegister(int /* regNum */, + double /* value */) { + _LIBUNWIND_ABORT("VE doesn't have float registers"); +} + +inline bool Registers_ve::validVectorRegister(int /* regNum */) const { + return false; +} + +inline v128 Registers_ve::getVectorRegister(int /* regNum */) const { + _LIBUNWIND_ABORT("VE vector support not implemented"); +} + +inline void Registers_ve::setVectorRegister(int /* regNum */, + v128 /* value */) { + _LIBUNWIND_ABORT("VE vector support not implemented"); +} + +inline const char *Registers_ve::getRegisterName(int regNum) { + switch (regNum) { + case UNW_REG_IP: + return "ip"; + case UNW_REG_SP: + return "sp"; + case UNW_VE_VIXR: + return "vixr"; + case UNW_VE_VL: + return "vl"; + case UNW_VE_S0: + return "s0"; + case UNW_VE_S1: + return "s1"; + case UNW_VE_S2: + return "s2"; + case UNW_VE_S3: + return "s3"; + case UNW_VE_S4: + return "s4"; + case UNW_VE_S5: + return "s5"; + case UNW_VE_S6: + return "s6"; + case UNW_VE_S7: + return "s7"; + case UNW_VE_S8: + return "s8"; + case UNW_VE_S9: + return "s9"; + case UNW_VE_S10: + return "s10"; + case UNW_VE_S11: + return "s11"; + case UNW_VE_S12: + return "s12"; + case UNW_VE_S13: + return "s13"; + case UNW_VE_S14: + return "s14"; + case UNW_VE_S15: + return "s15"; + case UNW_VE_S16: + return "s16"; + case UNW_VE_S17: + return "s17"; + case UNW_VE_S18: + return "s18"; + case UNW_VE_S19: + return "s19"; + case UNW_VE_S20: + return "s20"; + case UNW_VE_S21: + return "s21"; + case UNW_VE_S22: + return "s22"; + case UNW_VE_S23: + return "s23"; + case UNW_VE_S24: + return "s24"; + case UNW_VE_S25: + return "s25"; + case UNW_VE_S26: + return "s26"; + case UNW_VE_S27: + return "s27"; + case UNW_VE_S28: + return "s28"; + case UNW_VE_S29: + return "s29"; + case UNW_VE_S30: + return "s30"; + case UNW_VE_S31: + return "s31"; + case UNW_VE_S32: + return "s32"; + case UNW_VE_S33: + return "s33"; + case UNW_VE_S34: + return "s34"; + case UNW_VE_S35: + return "s35"; + case UNW_VE_S36: + return "s36"; + case UNW_VE_S37: + return "s37"; + case UNW_VE_S38: + return "s38"; + case UNW_VE_S39: + return "s39"; + case UNW_VE_S40: + return "s40"; + case UNW_VE_S41: + return "s41"; + case UNW_VE_S42: + return "s42"; + case UNW_VE_S43: + return "s43"; + case UNW_VE_S44: + return "s44"; + case UNW_VE_S45: + return "s45"; + case UNW_VE_S46: + return "s46"; + case UNW_VE_S47: + return "s47"; + case UNW_VE_S48: + return "s48"; + case UNW_VE_S49: + return "s49"; + case UNW_VE_S50: + return "s50"; + case UNW_VE_S51: + return "s51"; + case UNW_VE_S52: + return "s52"; + case UNW_VE_S53: + return "s53"; + case UNW_VE_S54: + return "s54"; + case UNW_VE_S55: + return "s55"; + case UNW_VE_S56: + return "s56"; + case UNW_VE_S57: + return "s57"; + case UNW_VE_S58: + return "s58"; + case UNW_VE_S59: + return "s59"; + case UNW_VE_S60: + return "s60"; + case UNW_VE_S61: + return "s61"; + case UNW_VE_S62: + return "s62"; + case UNW_VE_S63: + return "s63"; + case UNW_VE_V0: + return "v0"; + case UNW_VE_V1: + return "v1"; + case UNW_VE_V2: + return "v2"; + case UNW_VE_V3: + return "v3"; + case UNW_VE_V4: + return "v4"; + case UNW_VE_V5: + return "v5"; + case UNW_VE_V6: + return "v6"; + case UNW_VE_V7: + return "v7"; + case UNW_VE_V8: + return "v8"; + case UNW_VE_V9: + return "v9"; + case UNW_VE_V10: + return "v10"; + case UNW_VE_V11: + return "v11"; + case UNW_VE_V12: + return "v12"; + case UNW_VE_V13: + return "v13"; + case UNW_VE_V14: + return "v14"; + case UNW_VE_V15: + return "v15"; + case UNW_VE_V16: + return "v16"; + case UNW_VE_V17: + return "v17"; + case UNW_VE_V18: + return "v18"; + case UNW_VE_V19: + return "v19"; + case UNW_VE_V20: + return "v20"; + case UNW_VE_V21: + return "v21"; + case UNW_VE_V22: + return "v22"; + case UNW_VE_V23: + return "v23"; + case UNW_VE_V24: + return "v24"; + case UNW_VE_V25: + return "v25"; + case UNW_VE_V26: + return "v26"; + case UNW_VE_V27: + return "v27"; + case UNW_VE_V28: + return "v28"; + case UNW_VE_V29: + return "v29"; + case UNW_VE_V30: + return "v30"; + case UNW_VE_V31: + return "v31"; + case UNW_VE_V32: + return "v32"; + case UNW_VE_V33: + return "v33"; + case UNW_VE_V34: + return "v34"; + case UNW_VE_V35: + return "v35"; + case UNW_VE_V36: + return "v36"; + case UNW_VE_V37: + return "v37"; + case UNW_VE_V38: + return "v38"; + case UNW_VE_V39: + return "v39"; + case UNW_VE_V40: + return "v40"; + case UNW_VE_V41: + return "v41"; + case UNW_VE_V42: + return "v42"; + case UNW_VE_V43: + return "v43"; + case UNW_VE_V44: + return "v44"; + case UNW_VE_V45: + return "v45"; + case UNW_VE_V46: + return "v46"; + case UNW_VE_V47: + return "v47"; + case UNW_VE_V48: + return "v48"; + case UNW_VE_V49: + return "v49"; + case UNW_VE_V50: + return "v50"; + case UNW_VE_V51: + return "v51"; + case UNW_VE_V52: + return "v52"; + case UNW_VE_V53: + return "v53"; + case UNW_VE_V54: + return "v54"; + case UNW_VE_V55: + return "v55"; + case UNW_VE_V56: + return "v56"; + case UNW_VE_V57: + return "v57"; + case UNW_VE_V58: + return "v58"; + case UNW_VE_V59: + return "v59"; + case UNW_VE_V60: + return "v60"; + case UNW_VE_V61: + return "v61"; + case UNW_VE_V62: + return "v62"; + case UNW_VE_V63: + return "v63"; + case UNW_VE_VM0: + return "vm0"; + case UNW_VE_VM1: + return "vm1"; + case UNW_VE_VM2: + return "vm2"; + case UNW_VE_VM3: + return "vm3"; + case UNW_VE_VM4: + return "vm4"; + case UNW_VE_VM5: + return "vm5"; + case UNW_VE_VM6: + return "vm6"; + case UNW_VE_VM7: + return "vm7"; + case UNW_VE_VM8: + return "vm8"; + case UNW_VE_VM9: + return "vm9"; + case UNW_VE_VM10: + return "vm10"; + case UNW_VE_VM11: + return "vm11"; + case UNW_VE_VM12: + return "vm12"; + case UNW_VE_VM13: + return "vm13"; + case UNW_VE_VM14: + return "vm14"; + case UNW_VE_VM15: + return "vm15"; + } + return "unknown register"; +} +#endif // _LIBUNWIND_TARGET_VE + } // namespace libunwind #endif // __REGISTERS_HPP__ diff --git a/libunwind/src/Unwind-seh.cpp b/libunwind/src/Unwind-seh.cpp index 403ab2d77110..6e2b4e73e41e 100644 --- a/libunwind/src/Unwind-seh.cpp +++ b/libunwind/src/Unwind-seh.cpp @@ -46,18 +46,6 @@ using namespace libunwind; /// handling. #define STATUS_GCC_UNWIND MAKE_GCC_EXCEPTION(1) // 0x21474343 -/// Class of foreign exceptions based on unrecognized SEH exceptions. -static const uint64_t kSEHExceptionClass = 0x434C4E4753454800; // CLNGSEH\0 - -/// Exception cleanup routine used by \c _GCC_specific_handler to -/// free foreign exceptions. -static void seh_exc_cleanup(_Unwind_Reason_Code urc, _Unwind_Exception *exc) { - (void)urc; - if (exc->exception_class != kSEHExceptionClass) - _LIBUNWIND_ABORT("SEH cleanup called on non-SEH exception"); - free(exc); -} - static int __unw_init_seh(unw_cursor_t *cursor, CONTEXT *ctx); static DISPATCHER_CONTEXT *__unw_seh_get_disp_ctx(unw_cursor_t *cursor); static void __unw_seh_set_disp_ctx(unw_cursor_t *cursor, @@ -108,10 +96,10 @@ _GCC_specific_handler(PEXCEPTION_RECORD ms_exc, PVOID frame, PCONTEXT ms_ctx, } } else { // Foreign exception. - exc = (_Unwind_Exception *)malloc(sizeof(_Unwind_Exception)); - exc->exception_class = kSEHExceptionClass; - exc->exception_cleanup = seh_exc_cleanup; - memset(exc->private_, 0, sizeof(exc->private_)); + // We can't interact with them (we don't know the original target frame + // that we should pass on to RtlUnwindEx in _Unwind_Resume), so just + // pass without calling our destructors here. + return ExceptionContinueSearch; } if (!ctx) { __unw_init_seh(&cursor, disp->ContextRecord); diff --git a/libunwind/src/Unwind-sjlj.c b/libunwind/src/Unwind-sjlj.c index 85a4cc3c69d6..fd2a95b74c44 100644 --- a/libunwind/src/Unwind-sjlj.c +++ b/libunwind/src/Unwind-sjlj.c @@ -32,11 +32,23 @@ struct _Unwind_FunctionContext { // next function in stack of handlers struct _Unwind_FunctionContext *prev; +#if defined(__ve__) + // VE requires to store 64 bit pointers in the buffer for SjLj execption. + // We expand the size of values defined here. This size must be matched + // to the size returned by TargetMachine::getSjLjDataSize(). + + // set by calling function before registering to be the landing pad + uint64_t resumeLocation; + + // set by personality handler to be parameters passed to landing pad function + uint64_t resumeParameters[4]; +#else // set by calling function before registering to be the landing pad uint32_t resumeLocation; // set by personality handler to be parameters passed to landing pad function uint32_t resumeParameters[4]; +#endif // set by calling function before registering _Unwind_Personality_Fn personality; // arm offset=24 diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp index f346c720d22c..e537ed84dd93 100644 --- a/libunwind/src/UnwindCursor.hpp +++ b/libunwind/src/UnwindCursor.hpp @@ -81,6 +81,7 @@ template <typename A> class _LIBUNWIND_HIDDEN DwarfFDECache { typedef typename A::pint_t pint_t; public: + static constexpr pint_t kSearchAll = static_cast<pint_t>(-1); 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); @@ -138,7 +139,7 @@ typename A::pint_t DwarfFDECache<A>::findFDE(pint_t mh, pint_t pc) { pint_t result = 0; _LIBUNWIND_LOG_IF_FALSE(_lock.lock_shared()); for (entry *p = _buffer; p < _bufferUsed; ++p) { - if ((mh == p->mh) || (mh == 0)) { + if ((mh == p->mh) || (mh == kSearchAll)) { if ((p->ip_start <= pc) && (pc < p->ip_end)) { result = p->fde; break; @@ -530,6 +531,8 @@ UnwindCursor<A, R>::UnwindCursor(unw_context_t *context, A &as) : _addressSpace(as), _unwindInfoMissing(false) { static_assert((check_fit<UnwindCursor<A, R>, unw_cursor_t>::does_fit), "UnwindCursor<> does not fit in unw_cursor_t"); + static_assert((alignof(UnwindCursor<A, R>) <= alignof(unw_cursor_t)), + "UnwindCursor<> requires more alignment than unw_cursor_t"); memset(&_info, 0, sizeof(_info)); memset(&_histTable, 0, sizeof(_histTable)); _dispContext.ContextRecord = &_msContext; @@ -922,7 +925,29 @@ private: } #endif +#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64) + bool setInfoForSigReturn() { + R dummy; + return setInfoForSigReturn(dummy); + } + int stepThroughSigReturn() { + R dummy; + return stepThroughSigReturn(dummy); + } + bool setInfoForSigReturn(Registers_arm64 &); + int stepThroughSigReturn(Registers_arm64 &); + template <typename Registers> bool setInfoForSigReturn(Registers &) { + return false; + } + template <typename Registers> int stepThroughSigReturn(Registers &) { + return UNW_STEP_END; + } +#endif + #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + bool getInfoFromFdeCie(const typename CFI_Parser<A>::FDE_Info &fdeInfo, + const typename CFI_Parser<A>::CIE_Info &cieInfo, + pint_t pc, uintptr_t dso_base); bool getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections §s, uint32_t fdeSectionOffsetHint=0); int stepWithDwarfFDE() { @@ -1173,6 +1198,9 @@ private: unw_proc_info_t _info; bool _unwindInfoMissing; bool _isSignalFrame; +#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64) + bool _isSigReturn = false; +#endif }; @@ -1182,6 +1210,8 @@ UnwindCursor<A, R>::UnwindCursor(unw_context_t *context, A &as) _isSignalFrame(false) { static_assert((check_fit<UnwindCursor<A, R>, unw_cursor_t>::does_fit), "UnwindCursor<> does not fit in unw_cursor_t"); + static_assert((alignof(UnwindCursor<A, R>) <= alignof(unw_cursor_t)), + "UnwindCursor<> requires more alignment than unw_cursor_t"); memset(&_info, 0, sizeof(_info)); } @@ -1473,6 +1503,32 @@ bool UnwindCursor<A, R>::getInfoFromEHABISection( #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) template <typename A, typename R> +bool UnwindCursor<A, R>::getInfoFromFdeCie( + const typename CFI_Parser<A>::FDE_Info &fdeInfo, + const typename CFI_Parser<A>::CIE_Info &cieInfo, pint_t pc, + uintptr_t dso_base) { + typename CFI_Parser<A>::PrologInfo prolog; + if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc, + R::getArch(), &prolog)) { + // Save off parsed FDE info + _info.start_ip = fdeInfo.pcStart; + _info.end_ip = fdeInfo.pcEnd; + _info.lsda = fdeInfo.lsda; + _info.handler = cieInfo.personality; + // Some frameless functions need SP altered when resuming in function, so + // propagate spExtraArgSize. + _info.gp = prolog.spExtraArgSize; + _info.flags = 0; + _info.format = dwarfEncoding(); + _info.unwind_info = fdeInfo.fdeStart; + _info.unwind_info_size = static_cast<uint32_t>(fdeInfo.fdeLength); + _info.extra = static_cast<unw_word_t>(dso_base); + return true; + } + return false; +} + +template <typename A, typename R> bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections §s, uint32_t fdeSectionOffsetHint) { @@ -1483,7 +1539,7 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc, // If compact encoding table gave offset into dwarf section, go directly there if (fdeSectionOffsetHint != 0) { foundFDE = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section, - (uint32_t)sects.dwarf_section_length, + sects.dwarf_section_length, sects.dwarf_section + fdeSectionOffsetHint, &fdeInfo, &cieInfo); } @@ -1500,7 +1556,7 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc, if (cachedFDE != 0) { foundFDE = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section, - (uint32_t)sects.dwarf_section_length, + sects.dwarf_section_length, cachedFDE, &fdeInfo, &cieInfo); foundInCache = foundFDE; } @@ -1508,25 +1564,11 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc, if (!foundFDE) { // Still not found, do full scan of __eh_frame section. foundFDE = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section, - (uint32_t)sects.dwarf_section_length, 0, + sects.dwarf_section_length, 0, &fdeInfo, &cieInfo); } if (foundFDE) { - typename CFI_Parser<A>::PrologInfo prolog; - if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc, - R::getArch(), &prolog)) { - // Save off parsed FDE info - _info.start_ip = fdeInfo.pcStart; - _info.end_ip = fdeInfo.pcEnd; - _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; - + if (getInfoFromFdeCie(fdeInfo, cieInfo, pc, 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)) { @@ -1759,12 +1801,12 @@ bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(pint_t pc, } } - // extact personality routine, if encoding says function has one + // extract 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()) { + if (personalityIndex >= sectionHeader.personalityArrayCount()) { _LIBUNWIND_DEBUG_LOG("found encoding 0x%08X with personality index %d, " "but personality table has only %d entries", encoding, personalityIndex, @@ -1853,7 +1895,11 @@ bool UnwindCursor<A, R>::getInfoFromSEH(pint_t pc) { template <typename A, typename R> void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) { - pint_t pc = (pint_t)this->getReg(UNW_REG_IP); +#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64) + _isSigReturn = false; +#endif + + pint_t pc = static_cast<pint_t>(this->getReg(UNW_REG_IP)); #if defined(_LIBUNWIND_ARM_EHABI) // Remove the thumb bit so the IP represents the actual instruction address. // This matches the behaviour of _Unwind_GetIP on arm. @@ -1926,68 +1972,102 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) { #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) // There is no static unwind info for this pc. Look to see if an FDE was // dynamically registered for it. - pint_t cachedFDE = DwarfFDECache<A>::findFDE(0, pc); + pint_t cachedFDE = DwarfFDECache<A>::findFDE(DwarfFDECache<A>::kSearchAll, + pc); if (cachedFDE != 0) { - CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo; - CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo; - const char *msg = CFI_Parser<A>::decodeFDE(_addressSpace, - cachedFDE, &fdeInfo, &cieInfo); - if (msg == NULL) { - typename CFI_Parser<A>::PrologInfo prolog; - if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, - pc, R::getArch(), &prolog)) { - // save off parsed FDE info - _info.start_ip = fdeInfo.pcStart; - _info.end_ip = fdeInfo.pcEnd; - _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; + typename CFI_Parser<A>::FDE_Info fdeInfo; + typename CFI_Parser<A>::CIE_Info cieInfo; + if (!CFI_Parser<A>::decodeFDE(_addressSpace, cachedFDE, &fdeInfo, &cieInfo)) + if (getInfoFromFdeCie(fdeInfo, cieInfo, pc, 0)) return; - } - } } // Lastly, ask AddressSpace object about platform specific ways to locate // other FDEs. pint_t fde; if (_addressSpace.findOtherFDE(pc, fde)) { - CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo; - CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo; + typename CFI_Parser<A>::FDE_Info fdeInfo; + typename CFI_Parser<A>::CIE_Info cieInfo; if (!CFI_Parser<A>::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<A>::PrologInfo prolog; - if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, - pc, R::getArch(), &prolog)) { - // save off parsed FDE info - _info.start_ip = fdeInfo.pcStart; - _info.end_ip = fdeInfo.pcEnd; - _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; + if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd)) + if (getInfoFromFdeCie(fdeInfo, cieInfo, pc, 0)) return; - } - } } } #endif // #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) +#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64) + if (setInfoForSigReturn()) + return; +#endif + // no unwind info, flag that we can't reliably unwind _unwindInfoMissing = true; } +#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64) +template <typename A, typename R> +bool UnwindCursor<A, R>::setInfoForSigReturn(Registers_arm64 &) { + // Look for the sigreturn trampoline. The trampoline's body is two + // specific instructions (see below). Typically the trampoline comes from the + // vDSO[1] (i.e. the __kernel_rt_sigreturn function). A libc might provide its + // own restorer function, though, or user-mode QEMU might write a trampoline + // onto the stack. + // + // This special code path is a fallback that is only used if the trampoline + // lacks proper (e.g. DWARF) unwind info. On AArch64, a new DWARF register + // constant for the PC needs to be defined before DWARF can handle a signal + // trampoline. This code may segfault if the target PC is unreadable, e.g.: + // - The PC points at a function compiled without unwind info, and which is + // part of an execute-only mapping (e.g. using -Wl,--execute-only). + // - The PC is invalid and happens to point to unreadable or unmapped memory. + // + // [1] https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/vdso/sigreturn.S + const pint_t pc = static_cast<pint_t>(this->getReg(UNW_REG_IP)); + // Look for instructions: mov x8, #0x8b; svc #0x0 + if (_addressSpace.get32(pc) == 0xd2801168 && + _addressSpace.get32(pc + 4) == 0xd4000001) { + _info = {}; + _isSigReturn = true; + return true; + } + return false; +} + +template <typename A, typename R> +int UnwindCursor<A, R>::stepThroughSigReturn(Registers_arm64 &) { + // In the signal trampoline frame, sp points to an rt_sigframe[1], which is: + // - 128-byte siginfo struct + // - ucontext struct: + // - 8-byte long (uc_flags) + // - 8-byte pointer (uc_link) + // - 24-byte stack_t + // - 128-byte signal set + // - 8 bytes of padding because sigcontext has 16-byte alignment + // - sigcontext/mcontext_t + // [1] https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/signal.c + const pint_t kOffsetSpToSigcontext = (128 + 8 + 8 + 24 + 128 + 8); // 304 + + // Offsets from sigcontext to each register. + const pint_t kOffsetGprs = 8; // offset to "__u64 regs[31]" field + const pint_t kOffsetSp = 256; // offset to "__u64 sp" field + const pint_t kOffsetPc = 264; // offset to "__u64 pc" field + + pint_t sigctx = _registers.getSP() + kOffsetSpToSigcontext; + + for (int i = 0; i <= 30; ++i) { + uint64_t value = _addressSpace.get64(sigctx + kOffsetGprs + + static_cast<pint_t>(i * 8)); + _registers.setRegister(UNW_ARM64_X0 + i, value); + } + _registers.setSP(_addressSpace.get64(sigctx + kOffsetSp)); + _registers.setIP(_addressSpace.get64(sigctx + kOffsetPc)); + _isSignalFrame = true; + return UNW_STEP_SUCCESS; +} +#endif // defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64) + template <typename A, typename R> int UnwindCursor<A, R>::step() { // Bottom of stack is defined is when unwind info cannot be found. @@ -1996,20 +2076,27 @@ int UnwindCursor<A, R>::step() { // Use unwinding info to modify register set as if function returned. int result; +#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64) + if (_isSigReturn) { + result = this->stepThroughSigReturn(); + } else +#endif + { #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) - result = this->stepWithCompactEncoding(); + result = this->stepWithCompactEncoding(); #elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) - result = this->stepWithSEHData(); + result = this->stepWithSEHData(); #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) - result = this->stepWithDwarfFDE(); + result = this->stepWithDwarfFDE(); #elif defined(_LIBUNWIND_ARM_EHABI) - result = this->stepWithEHABI(); + result = this->stepWithEHABI(); #else #error Need _LIBUNWIND_SUPPORT_COMPACT_UNWIND or \ _LIBUNWIND_SUPPORT_SEH_UNWIND or \ _LIBUNWIND_SUPPORT_DWARF_UNWIND or \ _LIBUNWIND_ARM_EHABI #endif + } // update info based on new PC if (result == UNW_STEP_SUCCESS) { diff --git a/libunwind/src/UnwindLevel1.c b/libunwind/src/UnwindLevel1.c index 3e75b5f13cd6..68e5e48b8c05 100644 --- a/libunwind/src/UnwindLevel1.c +++ b/libunwind/src/UnwindLevel1.c @@ -39,8 +39,7 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except __unw_init_local(cursor, uc); // Walk each frame looking for a place to stop. - bool handlerNotFound = true; - while (handlerNotFound) { + while (true) { // Ask libunwind to get next frame (skip over first which is // _Unwind_RaiseException). int stepResult = __unw_step(cursor); @@ -102,7 +101,6 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except 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(cursor, UNW_REG_SP, &sp); exception_object->private_2 = (uintptr_t)sp; _LIBUNWIND_TRACE_UNWINDING( diff --git a/libunwind/src/UnwindRegistersRestore.S b/libunwind/src/UnwindRegistersRestore.S index 5d5443215286..289afe98b0b2 100644 --- a/libunwind/src/UnwindRegistersRestore.S +++ b/libunwind/src/UnwindRegistersRestore.S @@ -13,14 +13,10 @@ #if !defined(__USING_SJLJ_EXCEPTIONS__) #if defined(__i386__) -DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_x866jumptoEv) +DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_jumpto) # -# void libunwind::Registers_x86::jumpto() +# extern "C" void __libunwind_Registers_x86_jumpto(Registers_x86 *); # -#if defined(_WIN32) -# On windows, the 'this' pointer is passed in ecx instead of on the stack - movl %ecx, %eax -#else # On entry: # + + # +-----------------------+ @@ -30,7 +26,6 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_x866jumptoEv) # +-----------------------+ <-- SP # + + movl 4(%esp), %eax -#endif # set up eax and ret on new stack location movl 28(%eax), %edx # edx holds new stack pointer subl $8,%edx @@ -60,9 +55,9 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_x866jumptoEv) #elif defined(__x86_64__) -DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind16Registers_x86_646jumptoEv) +DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_64_jumpto) # -# void libunwind::Registers_x86_64::jumpto() +# extern "C" void __libunwind_Registers_x86_64_jumpto(Registers_x86_64 *); # #if defined(_WIN64) # On entry, thread_state pointer is in rcx; move it into rdi @@ -175,7 +170,7 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_ppc646jumptoEv) PPC64_LR(30) PPC64_LR(31) -#ifdef PPC64_HAS_VMX +#if defined(__VSX__) // restore VS registers // (note that this also restores floating point registers and V registers, @@ -317,6 +312,7 @@ PPC64_CLVS_BOTTOM(n) PPC64_LF(30) PPC64_LF(31) +#if defined(__ALTIVEC__) // restore vector registers if any are in use ld %r5, PPC64_OFFS_VRSAVE(%r3) // test VRsave cmpwi %r5, 0 @@ -378,6 +374,7 @@ PPC64_CLV_UNALIGNED_BOTTOM(n) PPC64_CLV_UNALIGNEDh(31) #endif +#endif Lnovec: ld %r0, PPC64_OFFS_CR(%r3) @@ -436,6 +433,7 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv) lwz %r30,128(%r3) lwz %r31,132(%r3) +#ifndef __NO_FPRS__ // restore float registers lfd %f0, 160(%r3) lfd %f1, 168(%r3) @@ -469,7 +467,9 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv) lfd %f29,392(%r3) lfd %f30,400(%r3) lfd %f31,408(%r3) +#endif +#if defined(__ALTIVEC__) // restore vector registers if any are in use lwz %r5, 156(%r3) // test VRsave cmpwi %r5, 0 @@ -542,6 +542,7 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv) LOAD_VECTOR_UNALIGNEDh(29) LOAD_VECTOR_UNALIGNEDh(30) LOAD_VECTOR_UNALIGNEDh(31) +#endif Lnovec: lwz %r0, 136(%r3) // __cr @@ -560,13 +561,13 @@ Lnovec: #elif defined(__aarch64__) // -// void libunwind::Registers_arm64::jumpto() +// extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *); // // On entry: // thread_state pointer is in x0 // .p2align 2 -DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_arm646jumptoEv) +DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto) // skip restore of x0,x1 for now ldp x2, x3, [x0, #0x010] ldp x4, x5, [x0, #0x020] diff --git a/libunwind/src/UnwindRegistersSave.S b/libunwind/src/UnwindRegistersSave.S index 51bb9b0688fd..94fc8365455d 100644 --- a/libunwind/src/UnwindRegistersSave.S +++ b/libunwind/src/UnwindRegistersSave.S @@ -384,7 +384,7 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) mfvrsave %r0 std %r0, PPC64_OFFS_VRSAVE(%r3) -#ifdef PPC64_HAS_VMX +#if defined(__VSX__) // save VS registers // (note that this also saves floating point registers and V registers, // because part of VS is mapped to these registers) @@ -501,6 +501,7 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) PPC64_STF(30) PPC64_STF(31) +#if defined(__ALTIVEC__) // save vector registers // Use 16-bytes below the stack pointer as an @@ -549,6 +550,7 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) PPC64_STV_UNALIGNED(31) #endif +#endif li %r3, 0 // return UNW_ESUCCESS blr @@ -608,6 +610,7 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) mfctr %r0 stw %r0, 148(%r3) +#if !defined(__NO_FPRS__) // save float registers stfd %f0, 160(%r3) stfd %f1, 168(%r3) @@ -641,8 +644,9 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) stfd %f29,392(%r3) stfd %f30,400(%r3) stfd %f31,408(%r3) +#endif - +#if defined(__ALTIVEC__) // save vector registers subi %r4, %r1, 16 @@ -692,6 +696,7 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) SAVE_VECTOR_UNALIGNED(%v29, 424+0x1D0) SAVE_VECTOR_UNALIGNED(%v30, 424+0x1E0) SAVE_VECTOR_UNALIGNED(%v31, 424+0x1F0) +#endif li %r3, 0 // return UNW_ESUCCESS blr diff --git a/libunwind/src/Unwind_AppleExtras.cpp b/libunwind/src/Unwind_AppleExtras.cpp index 536303993eff..e3d41ca2b4e9 100644 --- a/libunwind/src/Unwind_AppleExtras.cpp +++ b/libunwind/src/Unwind_AppleExtras.cpp @@ -8,35 +8,6 @@ //===----------------------------------------------------------------------===// #include "config.h" -#include "AddressSpace.hpp" -#include "DwarfParser.hpp" - - -// private keymgr stuff -#define KEYMGR_GCC3_DW2_OBJ_LIST 302 -extern "C" { - extern void _keymgr_set_and_unlock_processwide_ptr(int key, void *ptr); - extern void *_keymgr_get_and_lock_processwide_ptr(int key); -} - -// undocumented libgcc "struct object" -struct libgcc_object { - void *start; - void *unused1; - void *unused2; - void *fde; - unsigned long encoding; - void *fde_end; - libgcc_object *next; -}; - -// undocumented libgcc "struct km_object_info" referenced by -// KEYMGR_GCC3_DW2_OBJ_LIST -struct libgcc_object_info { - libgcc_object *seen_objects; - libgcc_object *unseen_objects; - unsigned spare[2]; -}; // static linker symbols to prevent wrong two level namespace for _Unwind symbols @@ -140,44 +111,3 @@ NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Resume_or_Rethrow) NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Unregister) #endif // defined(_LIBUNWIND_BUILD_SJLJ_APIS) - - -namespace libunwind { - -_LIBUNWIND_HIDDEN -bool checkKeyMgrRegisteredFDEs(uintptr_t pc, void *&fde) { -#if __MAC_OS_X_VERSION_MIN_REQUIRED - // lastly check for old style keymgr registration of dynamically generated - // FDEs acquire exclusive access to libgcc_object_info - libgcc_object_info *head = (libgcc_object_info *) - _keymgr_get_and_lock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST); - if (head != NULL) { - // look at each FDE in keymgr - for (libgcc_object *ob = head->unseen_objects; ob != NULL; ob = ob->next) { - CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo; - CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo; - const char *msg = CFI_Parser<LocalAddressSpace>::decodeFDE( - LocalAddressSpace::sThisAddressSpace, - (uintptr_t)ob->fde, &fdeInfo, &cieInfo); - if (msg == NULL) { - // Check if this FDE is for a function that includes the pc - if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd)) { - fde = (void*)fdeInfo.pcStart; - _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, - head); - return true; - } - } - } - } - // release libgcc_object_info - _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, head); -#else - (void)pc; - (void)fde; -#endif - return false; -} - -} - diff --git a/libunwind/src/assembly.h b/libunwind/src/assembly.h index 4cf179e13edc..f2f7c848307e 100644 --- a/libunwind/src/assembly.h +++ b/libunwind/src/assembly.h @@ -25,9 +25,6 @@ #define PPC64_OFFS_VRSAVE 304 #define PPC64_OFFS_FP 312 #define PPC64_OFFS_V 824 -#ifdef _ARCH_PWR8 -#define PPC64_HAS_VMX -#endif #elif defined(__APPLE__) && defined(__aarch64__) #define SEPARATOR %% #else @@ -48,6 +45,24 @@ #define PPC64_OPD2 #endif +#if defined(__ARM_FEATURE_BTI_DEFAULT) + .pushsection ".note.gnu.property", "a" SEPARATOR \ + .balign 8 SEPARATOR \ + .long 4 SEPARATOR \ + .long 0x10 SEPARATOR \ + .long 0x5 SEPARATOR \ + .asciz "GNU" SEPARATOR \ + .long 0xc0000000 SEPARATOR /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */ \ + .long 4 SEPARATOR \ + .long 3 SEPARATOR /* GNU_PROPERTY_AARCH64_FEATURE_1_BTI AND */ \ + /* GNU_PROPERTY_AARCH64_FEATURE_1_PAC */ \ + .long 0 SEPARATOR \ + .popsection SEPARATOR +#define AARCH64_BTI bti c +#else +#define AARCH64_BTI +#endif + #define GLUE2(a, b) a ## b #define GLUE(a, b) GLUE2(a, b) #define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name) @@ -144,7 +159,8 @@ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ PPC64_OPD1 \ SYMBOL_NAME(name): \ - PPC64_OPD2 + PPC64_OPD2 \ + AARCH64_BTI #if defined(__arm__) #if !defined(__ARM_ARCH) diff --git a/libunwind/src/config.h b/libunwind/src/config.h index 842fd829af19..9efed05405c6 100644 --- a/libunwind/src/config.h +++ b/libunwind/src/config.h @@ -18,23 +18,15 @@ #include <stdint.h> #include <stdlib.h> -// 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 +#include <__libunwind_config.h> // Platform specific configuration defines. #ifdef __APPLE__ #if defined(FOR_DYLD) - #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND + #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1 #else - #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND - #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 + #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1 + #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 #endif #elif defined(_WIN32) #ifdef __SEH__ @@ -42,8 +34,19 @@ #else #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 #endif +#elif defined(_LIBUNWIND_IS_BAREMETAL) + #if !defined(_LIBUNWIND_ARM_EHABI) + #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 + #define _LIBUNWIND_SUPPORT_DWARF_INDEX 1 + #endif +#elif defined(__BIONIC__) && defined(_LIBUNWIND_ARM_EHABI) + // For ARM EHABI, Bionic didn't implement dl_iterate_phdr until API 21. After + // API 21, dl_iterate_phdr exists, but dl_unwind_find_exidx is much faster. + #define _LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX 1 #else - #if defined(__ARM_DWARF_EH__) || !defined(__arm__) + // Assume an ELF system with a dl_iterate_phdr function. + #define _LIBUNWIND_USE_DL_ITERATE_PHDR 1 + #if !defined(_LIBUNWIND_ARM_EHABI) #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 #define _LIBUNWIND_SUPPORT_DWARF_INDEX 1 #endif @@ -91,6 +94,8 @@ #error Unsupported target #endif +// Apple/armv7k defaults to DWARF/Compact unwinding, but its libunwind also +// needs to include the SJLJ APIs. #if (defined(__APPLE__) && defined(__arm__)) || defined(__USING_SJLJ_EXCEPTIONS__) #define _LIBUNWIND_BUILD_SJLJ_APIS #endif @@ -111,8 +116,27 @@ #endif #endif -#if defined(__powerpc64__) && defined(_ARCH_PWR8) -#define PPC64_HAS_VMX +#ifndef _LIBUNWIND_REMEMBER_HEAP_ALLOC +#if defined(_LIBUNWIND_REMEMBER_STACK_ALLOC) || defined(__APPLE__) || \ + defined(__linux__) || defined(__ANDROID__) || defined(__MINGW32__) || \ + defined(_LIBUNWIND_IS_BAREMETAL) +#define _LIBUNWIND_REMEMBER_ALLOC(_size) alloca(_size) +#define _LIBUNWIND_REMEMBER_FREE(_ptr) \ + do { \ + } while (0) +#elif defined(_WIN32) +#define _LIBUNWIND_REMEMBER_ALLOC(_size) _malloca(_size) +#define _LIBUNWIND_REMEMBER_FREE(_ptr) _freea(_ptr) +#define _LIBUNWIND_REMEMBER_CLEANUP_NEEDED +#else +#define _LIBUNWIND_REMEMBER_ALLOC(_size) malloc(_size) +#define _LIBUNWIND_REMEMBER_FREE(_ptr) free(_ptr) +#define _LIBUNWIND_REMEMBER_CLEANUP_NEEDED +#endif +#else /* _LIBUNWIND_REMEMBER_HEAP_ALLOC */ +#define _LIBUNWIND_REMEMBER_ALLOC(_size) malloc(_size) +#define _LIBUNWIND_REMEMBER_FREE(_ptr) free(_ptr) +#define _LIBUNWIND_REMEMBER_CLEANUP_NEEDED #endif #if defined(NDEBUG) && defined(_LIBUNWIND_IS_BAREMETAL) diff --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp index fd079da30895..c21461b1f480 100644 --- a/libunwind/src/libunwind.cpp +++ b/libunwind/src/libunwind.cpp @@ -62,6 +62,8 @@ _LIBUNWIND_HIDDEN int __unw_init_local(unw_cursor_t *cursor, # define REGISTER_KIND Registers_sparc #elif defined(__riscv) && __riscv_xlen == 64 # define REGISTER_KIND Registers_riscv +#elif defined(__ve__) +# define REGISTER_KIND Registers_ve #else # error Architecture not supported #endif |