diff options
author | Nico Weber <nicolasweber@gmx.de> | 2014-06-23 17:00:44 -0700 |
---|---|---|
committer | Andrew Hsieh <andrewhsieh@google.com> | 2014-06-23 17:04:56 -0700 |
commit | 2569ad3ea4275b371c9cccfb4fb42183838a44e1 (patch) | |
tree | fc982c942527cf95abbe21bb07c5dde632aa7583 | |
parent | 94405da05acaf22a14495cdc957db186a87312c0 (diff) | |
download | ndk-2569ad3ea4275b371c9cccfb4fb42183838a44e1.tar.gz |
Sync android/support and libc++abi
to https://github.com/awong-dev/ndk b7e77cb5897f3355ce66277e303f4b2396cc3c9c
with feedback from upstream and arm64 fixes
Change-Id: I2cde541d8ac788c8b6234791f5af39fcf6af91e1
15 files changed, 1047 insertions, 740 deletions
diff --git a/build/tools/build-cxx-stl.sh b/build/tools/build-cxx-stl.sh index 0afd05eac..f38c772c9 100755 --- a/build/tools/build-cxx-stl.sh +++ b/build/tools/build-cxx-stl.sh @@ -308,7 +308,7 @@ LIBCXXABI_SOURCES=\ ../llvm-libc++abi/libcxxabi/src/stdexcept.cpp \ ../llvm-libc++abi/libcxxabi/src/typeinfo.cpp \ ../llvm-libc++abi/libcxxabi/src/Unwind/libunwind.cpp \ -../llvm-libc++abi/libcxxabi/src/Unwind/Unwind-arm.cpp \ +../llvm-libc++abi/libcxxabi/src/Unwind/Unwind-EHABI.cpp \ ../llvm-libc++abi/libcxxabi/src/Unwind/UnwindLevel1.c \ ../llvm-libc++abi/libcxxabi/src/Unwind/UnwindLevel1-gcc-ext.c \ ../llvm-libc++abi/libcxxabi/src/Unwind/UnwindRegistersRestore.S \ diff --git a/sources/android/support/src/stdio/stdio_impl.c b/sources/android/support/src/stdio/stdio_impl.c index e3c442dee..e06d5267c 100644 --- a/sources/android/support/src/stdio/stdio_impl.c +++ b/sources/android/support/src/stdio/stdio_impl.c @@ -1,5 +1,6 @@ #include <stdio.h> #include <wchar.h> +#include <stdlib.h> #include <string.h> #define _STDIO_IMPL_NO_REDIRECT_MACROS @@ -12,7 +13,7 @@ void fake_file_init_file(FakeFILE* file, FILE* f) { void fake_file_init_buffer(FakeFILE* file, char* buffer, size_t buffer_size) { memset(file, 0, sizeof(*file)); - file->buffer = buffer; + file->buffer = (void*)buffer; file->buffer_pos = 0; file->buffer_size = buffer_size; } diff --git a/sources/android/support/src/stdio/strtod.c b/sources/android/support/src/stdio/strtod.c index daea37c3b..3f4a9a14f 100644 --- a/sources/android/support/src/stdio/strtod.c +++ b/sources/android/support/src/stdio/strtod.c @@ -94,6 +94,9 @@ #define ANDROID_CHANGES #ifdef ANDROID_CHANGES +/* Needs to be above math.h include below */ +#include "fpmath.h" + #include <pthread.h> #define mutex_lock(x) pthread_mutex_lock(x) #define mutex_unlock(x) pthread_mutex_unlock(x) @@ -2987,7 +2990,6 @@ __dtoa } #include <limits.h> -#include "fpmath.h" char * rv_alloc(int i) diff --git a/sources/android/support/src/stdio/vfprintf.c b/sources/android/support/src/stdio/vfprintf.c index 5789acfdb..06c722322 100644 --- a/sources/android/support/src/stdio/vfprintf.c +++ b/sources/android/support/src/stdio/vfprintf.c @@ -27,6 +27,7 @@ #include <limits.h> #include <string.h> #include <stdarg.h> +#include <stdlib.h> #include <wchar.h> #include <inttypes.h> #include <math.h> diff --git a/sources/android/support/src/wcstox/shgetc.h b/sources/android/support/src/wcstox/shgetc.h index 72fa870a4..018d1a9a1 100644 --- a/sources/android/support/src/wcstox/shgetc.h +++ b/sources/android/support/src/wcstox/shgetc.h @@ -27,7 +27,7 @@ void shinit_wcstring(struct fake_file_t *, const wchar_t *wcs); int shgetc(struct fake_file_t *); // Back-track one character, must not be called more times than shgetc() -void shungetc(struct fake_file_t *); +void shunget(struct fake_file_t *); // This will be called with a value of 0 for |lim| to force rewinding // to the start of the string. In Musl, this is also used in different diff --git a/sources/android/support/src/wcstox/wcstol.c b/sources/android/support/src/wcstox/wcstol.c index d126cab78..ea86704c0 100644 --- a/sources/android/support/src/wcstox/wcstol.c +++ b/sources/android/support/src/wcstox/wcstol.c @@ -11,13 +11,13 @@ static unsigned long long wcstox(const wchar_t * restrict s, unsigned long long lim) { struct fake_file_t f; - const wchar_t *t = s; + wchar_t *t = (wchar_t *)s; while (iswspace(*t)) t++; shinit_wcstring(&f, t); unsigned long long y = __intscan(&f, base, 1, lim); if (p) { size_t cnt = shcnt(&f); - *p = cnt ? t + cnt : (const wchar_t *)s; + *p = cnt ? t + cnt : (wchar_t *)s; } return y; } diff --git a/sources/cxx-stl/llvm-libc++abi/libcxxabi/include/unwind.h b/sources/cxx-stl/llvm-libc++abi/libcxxabi/include/unwind.h index 1f715b1d7..7d16f0270 100644 --- a/sources/cxx-stl/llvm-libc++abi/libcxxabi/include/unwind.h +++ b/sources/cxx-stl/llvm-libc++abi/libcxxabi/include/unwind.h @@ -136,6 +136,15 @@ typedef _Unwind_Reason_Code (*__personality_routine) uint64_t exceptionClass, _Unwind_Exception* exceptionObject, struct _Unwind_Context* context); + +typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) + (int version, + _Unwind_Action actions, + uint64_t exceptionClass, + struct _Unwind_Exception *exceptionObject, + struct _Unwind_Context *context, + void *stop_parameter ); + #endif #ifdef __cplusplus diff --git a/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/Unwind/Unwind-EHABI.cpp b/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/Unwind/Unwind-EHABI.cpp new file mode 100644 index 000000000..f4619f08d --- /dev/null +++ b/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/Unwind/Unwind-EHABI.cpp @@ -0,0 +1,952 @@ +//===--------------------------- Unwind-EHABI.cpp -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// +// Implements ARM zero-cost C++ exceptions +// +//===----------------------------------------------------------------------===// + +#include <unwind.h> + +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "config.h" +#include "libunwind.h" +#include "unwind.h" +#include "../private_typeinfo.h" + +#if LIBCXXABI_ARM_EHABI +namespace { + +// Strange order: take words in order, but inside word, take from most to least +// signinficant byte. +uint8_t getByte(uint32_t* data, size_t offset) { + uint8_t* byteData = reinterpret_cast<uint8_t*>(data); + return byteData[(offset & ~0x03) + (3 - (offset&0x03))]; +} + +const char* getNextWord(const char* data, uint32_t* out) { + *out = *reinterpret_cast<const uint32_t*>(data); + return data + 4; +} + +const char* getNextNibble(const char* data, uint32_t* out) { + *out = *reinterpret_cast<const uint16_t*>(data); + return data + 2; +} + +static inline uint32_t signExtendPrel31(uint32_t data) { + return data | ((data & 0x40000000u) << 1); +} + +struct Descriptor { + // See # 9.2 + typedef enum { + SU16 = 0, // Short descriptor, 16-bit entries + LU16 = 1, // Long descriptor, 16-bit entries + LU32 = 3, // Long descriptor, 32-bit entries + RESERVED0 = 4, RESERVED1 = 5, RESERVED2 = 6, RESERVED3 = 7, + RESERVED4 = 8, RESERVED5 = 9, RESERVED6 = 10, RESERVED7 = 11, + RESERVED8 = 12, RESERVED9 = 13, RESERVED10 = 14, RESERVED11 = 15 + } Format; + + // See # 9.2 + typedef enum { + CLEANUP = 0x0, + FUNC = 0x1, + CATCH = 0x2, + INVALID = 0x4 + } Kind; +}; + +_Unwind_Reason_Code ProcessDescriptors( + _Unwind_State state, + _Unwind_Control_Block* ucbp, + struct _Unwind_Context* context, + Descriptor::Format format, + const char* descriptorStart, + int flags) { + // EHT is inlined in the index using compact form. No descriptors. #5 + if (flags & 0x1) + return _URC_CONTINUE_UNWIND; + + const char* descriptor = descriptorStart; + uint32_t descriptorWord; + getNextWord(descriptor, &descriptorWord); + while (descriptorWord) { + // Read descriptor based on # 9.2. + uint32_t length; + uint32_t offset; + switch (format) { + case Descriptor::LU32: + descriptor = getNextWord(descriptor, &length); + descriptor = getNextWord(descriptor, &offset); + case Descriptor::LU16: + descriptor = getNextNibble(descriptor, &length); + descriptor = getNextNibble(descriptor, &offset); + default: + assert(false); + return _URC_FAILURE; + } + + // See # 9.2 table for decoding the kind of descriptor. It's a 2-bit value. + Descriptor::Kind kind = + static_cast<Descriptor::Kind>((length & 0x1) | ((offset & 0x1) << 1)); + + // Clear off flag from last bit. + length &= ~1; + offset &= ~1; + uintptr_t scopeStart = ucbp->pr_cache.fnstart + offset; + uintptr_t scopeEnd = scopeStart + length; + uintptr_t pc = _Unwind_GetIP(context); + bool isInScope = (scopeStart <= pc) && (pc < scopeEnd); + + switch (kind) { + case Descriptor::CLEANUP: { + // TODO(ajwong): Handle cleanup descriptors. + break; + } + case Descriptor::FUNC: { + // TODO(ajwong): Handle function descriptors. + break; + } + case Descriptor::CATCH: { + // Catch descriptors require gobbling one more word. + uint32_t landing_pad; + descriptor = getNextWord(descriptor, &landing_pad); + + if (isInScope) { + // TODO(ajwong): This is only phase1 compatible logic. Implement + // phase2. + bool is_reference_type = landing_pad & 0x80000000; + landing_pad = signExtendPrel31(landing_pad & ~0x80000000); + if (landing_pad == 0xffffffff) { + return _URC_HANDLER_FOUND; + } else if (landing_pad == 0xfffffffe ) { + return _URC_FAILURE; + } else { + void* matched_object; + /* + if (__cxxabiv1::__cxa_type_match( + ucbp, reinterpret_cast<const std::type_info *>(landing_pad), + is_reference_type, + &matched_object) != __cxxabiv1::ctm_failed) + return _URC_HANDLER_FOUND; + */ + _LIBUNWIND_ABORT("Type matching not implemented"); + } + } + break; + } + default: + _LIBUNWIND_ABORT("Invalid descriptor kind found."); + }; + + getNextWord(descriptor, &descriptorWord); + } + + return _URC_CONTINUE_UNWIND; +} + +_Unwind_Reason_Code unwindOneFrame( + _Unwind_State state, + _Unwind_Control_Block* ucbp, + struct _Unwind_Context* context) { + // Read the compact model EHT entry's header # 6.3 + uint32_t* unwindingData = ucbp->pr_cache.ehtp; + uint32_t unwindInfo = *unwindingData; + assert((unwindInfo & 0xf0000000) == 0x80000000 && "Must be a compact entry"); + Descriptor::Format format = + static_cast<Descriptor::Format>((unwindInfo & 0x0f000000) >> 24); + size_t len = 0; + size_t startOffset = 0; + switch (format) { + case Descriptor::SU16: + len = 4; + startOffset = 1; + break; + case Descriptor::LU16: + case Descriptor::LU32: + len = 4 + 4 * ((unwindInfo & 0x00ff0000) >> 16); + startOffset = 2; + break; + default: + return _URC_FAILURE; + } + + // Handle descriptors before unwinding so they are processed in the context + // of the correct stack frame. + _Unwind_Reason_Code result = + ProcessDescriptors( + state, ucbp, context, format, + reinterpret_cast<const char*>(ucbp->pr_cache.ehtp) + len, + ucbp->pr_cache.additional); + + if (result != _URC_CONTINUE_UNWIND) + return result; + + return _Unwind_VRS_Interpret(context, unwindingData, startOffset, len); +} + +// Generates mask discriminator for _Unwind_VRS_Pop, e.g. for _UVRSC_CORE / +// _UVRSD_UINT32. +uint32_t RegisterMask(uint8_t start, uint8_t count_minus_one) { + return ((1U << (count_minus_one + 1)) - 1) << start; +} + +// Generates mask discriminator for _Unwind_VRS_Pop, e.g. for _UVRSC_VFP / +// _UVRSD_DOUBLE. +uint32_t RegisterRange(uint8_t start, uint8_t count_minus_one) { + return (start << 16) | (count_minus_one + 1); +} + +} // end anonymous namespace + +_Unwind_Reason_Code _Unwind_VRS_Interpret( + _Unwind_Context* context, + uint32_t* data, + size_t offset, + size_t len) { + bool wrotePC = false; + bool finish = false; + while (offset < len && !finish) { + uint8_t byte = getByte(data, offset++); + if ((byte & 0x80) == 0) { + uint32_t sp; + _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp); + if (byte & 0x40) + sp -= ((byte & 0x3f) << 2) + 4; + else + sp += (byte << 2) + 4; + _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp); + } else { + switch (byte & 0xf0) { + case 0x80: { + if (offset >= len) + return _URC_FAILURE; + uint16_t registers = + ((byte & 0x0f) << 12) | (getByte(data, offset++) << 4); + if (!registers) + return _URC_FAILURE; + if (registers & (1<<15)) + wrotePC = true; + _Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32); + break; + } + case 0x90: { + uint8_t reg = byte & 0x0f; + if (reg == 13 || reg == 15) + return _URC_FAILURE; + uint32_t sp; + _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_R0 + reg, + _UVRSD_UINT32, &sp); + _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, + &sp); + break; + } + case 0xa0: { + uint32_t registers = RegisterMask(4, byte & 0x07); + if (byte & 0x08) + registers |= 1<<14; + _Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32); + break; + } + case 0xb0: { + switch (byte) { + case 0xb0: + finish = true; + break; + case 0xb1: { + if (offset >= len) + return _URC_FAILURE; + uint8_t registers = getByte(data, offset++); + if (registers & 0xf0 || !registers) + return _URC_FAILURE; + _Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32); + break; + } + case 0xb2: { + uint32_t addend = 0; + uint32_t shift = 0; + // This decodes a uleb128 value. + while (true) { + if (offset >= len) + return _URC_FAILURE; + uint32_t v = getByte(data, offset++); + addend |= (v & 0x7f) << shift; + if ((v & 0x80) == 0) + break; + shift += 7; + } + uint32_t sp; + _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, + &sp); + sp += 0x204 + (addend << 2); + _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, + &sp); + break; + } + case 0xb3: { + uint8_t v = getByte(data, offset++); + _Unwind_VRS_Pop(context, _UVRSC_VFP, + RegisterRange(v >> 4, v & 0x0f), _UVRSD_VFPX); + break; + } + case 0xb4: + case 0xb5: + case 0xb6: + case 0xb7: + return _URC_FAILURE; + default: + _Unwind_VRS_Pop(context, _UVRSC_VFP, + RegisterRange(8, byte & 0x07), _UVRSD_VFPX); + break; + } + break; + } + case 0xc0: { + switch (byte) { + case 0xc0: + case 0xc1: + case 0xc2: + case 0xc3: + case 0xc4: + case 0xc5: + _Unwind_VRS_Pop(context, _UVRSC_WMMXD, + RegisterRange(10, byte & 0x7), _UVRSD_DOUBLE); + break; + case 0xc6: { + uint8_t v = getByte(data, offset++); + uint8_t start = v >> 4; + uint8_t count_minus_one = v & 0xf; + if (start + count_minus_one >= 16) + return _URC_FAILURE; + _Unwind_VRS_Pop(context, _UVRSC_WMMXD, + RegisterRange(start, count_minus_one), + _UVRSD_DOUBLE); + break; + } + case 0xc7: { + uint8_t v = getByte(data, offset++); + if (!v || v & 0xf0) + return _URC_FAILURE; + _Unwind_VRS_Pop(context, _UVRSC_WMMXC, v, _UVRSD_DOUBLE); + break; + } + case 0xc8: + case 0xc9: { + uint8_t v = getByte(data, offset++); + uint8_t start = ((byte == 0xc8) ? 16 : 0) + (v >> 4); + uint8_t count_minus_one = v & 0xf; + if (start + count_minus_one >= 32) + return _URC_FAILURE; + _Unwind_VRS_Pop(context, _UVRSC_VFP, + RegisterRange(start, count_minus_one), + _UVRSD_DOUBLE); + break; + } + default: + return _URC_FAILURE; + } + break; + } + case 0xd0: { + if (byte & 0x08) + return _URC_FAILURE; + _Unwind_VRS_Pop(context, _UVRSC_VFP, RegisterRange(8, byte & 0x7), + _UVRSD_DOUBLE); + break; + } + default: + return _URC_FAILURE; + } + } + } + if (!wrotePC) { + uint32_t lr; + _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_LR, _UVRSD_UINT32, &lr); + _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_IP, _UVRSD_UINT32, &lr); + } + return _URC_CONTINUE_UNWIND; +} + +extern "C" _Unwind_Reason_Code __aeabi_unwind_cpp_pr0( + _Unwind_State state, + _Unwind_Control_Block *ucbp, + _Unwind_Context *context) { + return unwindOneFrame(state, ucbp, context); +} + +extern "C" _Unwind_Reason_Code __aeabi_unwind_cpp_pr1( + _Unwind_State state, + _Unwind_Control_Block *ucbp, + _Unwind_Context *context) { + return unwindOneFrame(state, ucbp, context); +} + +extern "C" _Unwind_Reason_Code __aeabi_unwind_cpp_pr2( + _Unwind_State state, + _Unwind_Control_Block *ucbp, + _Unwind_Context *context) { + return unwindOneFrame(state, ucbp, context); +} + +static _Unwind_Reason_Code +unwind_phase1(unw_context_t *uc, _Unwind_Exception *exception_object) { + // EHABI #7.3 discusses preserving the VRS in a "temporary VRS" during + // phase 1 and then restoring it to the "primary VRS" for phase 2. The + // effect is phase 2 doesn't see any of the VRS manipulations from phase 1. + // In this implementation, the phases don't share the VRS backing store. + // Instead, they are passed the original |uc| and they create a new VRS + // from scratch thus achieving the same effect. + unw_cursor_t cursor1; + unw_init_local(&cursor1, uc); + + // Walk each frame looking for a place to stop. + for (bool handlerNotFound = true; handlerNotFound;) { + + // Ask libuwind to get next frame (skip over first which is + // _Unwind_RaiseException). + int stepResult = unw_step(&cursor1); + if (stepResult == 0) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step() reached " + "bottom => _URC_END_OF_STACK\n", + exception_object); + return _URC_END_OF_STACK; + } else if (stepResult < 0) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step failed => " + "_URC_FATAL_PHASE1_ERROR\n", + exception_object); + return _URC_FATAL_PHASE1_ERROR; + } + + // See if frame has code to run (has personality routine). + unw_proc_info_t frameInfo; + unw_word_t sp; + if (unw_get_proc_info(&cursor1, &frameInfo) != UNW_ESUCCESS) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_get_proc_info " + "failed => _URC_FATAL_PHASE1_ERROR\n", + exception_object); + return _URC_FATAL_PHASE1_ERROR; + } + + // When tracing, print state information. + if (_LIBUNWIND_TRACING_UNWINDING) { + char functionName[512]; + unw_word_t offset; + if ((unw_get_proc_name(&cursor1, functionName, 512, &offset) != + UNW_ESUCCESS) || (frameInfo.start_ip + offset > frameInfo.end_ip)) + strcpy(functionName, ".anonymous."); + unw_word_t pc; + unw_get_reg(&cursor1, UNW_REG_IP, &pc); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): pc=0x%llX, start_ip=0x%llX, func=%s, " + "lsda=0x%llX, personality=0x%llX\n", + exception_object, (long long)pc, (long long)frameInfo.start_ip, + functionName, (long long)frameInfo.lsda, + (long long)frameInfo.handler); + } + + // If there is a personality routine, ask it if it will want to stop at + // this frame. + if (frameInfo.handler != 0) { + __personality_routine p = + (__personality_routine)(long)(frameInfo.handler); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): calling personality function %p\n", + exception_object, p); + struct _Unwind_Context *context = (struct _Unwind_Context *)(&cursor1); + exception_object->pr_cache.fnstart = frameInfo.start_ip; + exception_object->pr_cache.ehtp = + (_Unwind_EHT_Header *)frameInfo.unwind_info; + exception_object->pr_cache.additional = frameInfo.flags; + _Unwind_Reason_Code personalityResult = + (*p)(_US_VIRTUAL_UNWIND_FRAME, exception_object, context); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): personality result %d " + "start_ip %x ehtp %p additional %x\n", + exception_object, personalityResult, + exception_object->pr_cache.fnstart, exception_object->pr_cache.ehtp, + exception_object->pr_cache.additional); + switch (personalityResult) { + case _URC_HANDLER_FOUND: + // found a catch clause or locals that need destructing in this frame + // stop search and remember stack pointer at the frame + handlerNotFound = false; + // p should have initialized barrier_cache. EHABI #7.3.5 + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): " + "_URC_HANDLER_FOUND \n", + exception_object); + return _URC_NO_REASON; + + case _URC_CONTINUE_UNWIND: + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", + exception_object); + // continue unwinding + break; + + // EHABI #7.3.3 + case _URC_FAILURE: + return _URC_FAILURE; + + default: + // something went wrong + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n", + exception_object); + return _URC_FATAL_PHASE1_ERROR; + } + } + } + return _URC_NO_REASON; +} + +static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, + _Unwind_Exception *exception_object, + bool resume) { + // See comment at the start of unwind_phase1 regarding VRS integrity. + unw_cursor_t cursor2; + unw_init_local(&cursor2, uc); + + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)\n", exception_object); + int frame_count = 0; + + // Walk each frame until we reach where search phase said to stop. + while (true) { + // Ask libuwind to get next frame (skip over first which is + // _Unwind_RaiseException or _Unwind_Resume). + // + // Resume only ever makes sense for 1 frame. + _Unwind_State state = + resume ? _US_UNWIND_FRAME_RESUME : _US_UNWIND_FRAME_STARTING; + if (resume && frame_count == 1) { + // On a resume, first unwind the _Unwind_Resume() frame. The next frame + // is now the landing pad for the cleanup from a previous execution of + // phase2. To continue unwindingly correctly, replace VRS[15] with the + // IP of the frame that the previous run of phase2 installed the context + // for. After this, continue unwinding as if normal. + // + // See #7.4.6 for details. + unw_set_reg(&cursor2, UNW_REG_IP, + exception_object->unwinder_cache.reserved2); + resume = false; + } + + int stepResult = unw_step(&cursor2); + if (stepResult == 0) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached " + "bottom => _URC_END_OF_STACK\n", + exception_object); + return _URC_END_OF_STACK; + } else if (stepResult < 0) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step failed => " + "_URC_FATAL_PHASE1_ERROR\n", + exception_object); + return _URC_FATAL_PHASE2_ERROR; + } + + // Get info about this frame. + unw_word_t sp; + unw_proc_info_t frameInfo; + unw_get_reg(&cursor2, UNW_REG_SP, &sp); + if (unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_get_proc_info " + "failed => _URC_FATAL_PHASE1_ERROR\n", + exception_object); + return _URC_FATAL_PHASE2_ERROR; + } + + // When tracing, print state information. + if (_LIBUNWIND_TRACING_UNWINDING) { + char functionName[512]; + unw_word_t offset; + if ((unw_get_proc_name(&cursor2, functionName, 512, &offset) != + UNW_ESUCCESS) || (frameInfo.start_ip + offset > frameInfo.end_ip)) + strcpy(functionName, ".anonymous."); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): start_ip=0x%llX, func=%s, sp=0x%llX, " + "lsda=0x%llX, personality=0x%llX\n", + exception_object, (long long)frameInfo.start_ip, functionName, + (long long)sp, (long long)frameInfo.lsda, + (long long)frameInfo.handler); + } + + // If there is a personality routine, tell it we are unwinding. + if (frameInfo.handler != 0) { + __personality_routine p = + (__personality_routine)(long)(frameInfo.handler); + struct _Unwind_Context *context = (struct _Unwind_Context *)(&cursor2); + // EHABI #7.2 + exception_object->pr_cache.fnstart = frameInfo.start_ip; + exception_object->pr_cache.ehtp = + (_Unwind_EHT_Header *)frameInfo.unwind_info; + exception_object->pr_cache.additional = frameInfo.flags; + _Unwind_Reason_Code personalityResult = + (*p)(state, exception_object, context); + switch (personalityResult) { + case _URC_CONTINUE_UNWIND: + // Continue unwinding + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", + exception_object); + // EHABI #7.2 + if (sp == exception_object->barrier_cache.sp) { + // Phase 1 said we would stop at this frame, but we did not... + _LIBUNWIND_ABORT("during phase1 personality function said it would " + "stop here, but now in phase2 it did not stop here"); + } + break; + case _URC_INSTALL_CONTEXT: + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT\n", + exception_object); + // Personality routine says to transfer control to landing pad. + // We may get control back if landing pad calls _Unwind_Resume(). + if (_LIBUNWIND_TRACING_UNWINDING) { + unw_word_t pc; + unw_get_reg(&cursor2, UNW_REG_IP, &pc); + unw_get_reg(&cursor2, UNW_REG_SP, &sp); + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering " + "user code with ip=0x%llX, sp=0x%llX\n", + exception_object, (long long)pc, + (long long)sp); + } + + { + // EHABI #7.4.1 says we need to preserve pc for when _Unwind_Resume + // is called back, to find this same frame. + unw_word_t pc; + unw_get_reg(&cursor2, UNW_REG_IP, &pc); + exception_object->unwinder_cache.reserved2 = (uint32_t)pc; + } + unw_resume(&cursor2); + // unw_resume() only returns if there was an error. + return _URC_FATAL_PHASE2_ERROR; + + // # EHABI #7.4.3 + case _URC_FAILURE: + abort(); + + default: + // Personality routine returned an unknown result code. + _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d", + personalityResult); + return _URC_FATAL_PHASE2_ERROR; + } + } + frame_count++; + } + + // Clean up phase did not resume at the frame that the search phase + // said it would... + return _URC_FATAL_PHASE2_ERROR; +} + +/// Called by __cxa_throw. Only returns if there is a fatal error. +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_RaiseException(_Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)\n", + exception_object); + unw_context_t uc; + unw_getcontext(&uc); + + // This field for is for compatibility with GCC to say this isn't a forced + // unwind. EHABI #7.2 + exception_object->unwinder_cache.reserved1 = 0; + + // phase 1: the search phase + _Unwind_Reason_Code phase1 = unwind_phase1(&uc, exception_object); + if (phase1 != _URC_NO_REASON) + return phase1; + + // phase 2: the clean up phase + return unwind_phase2(&uc, exception_object, false); +} + +_LIBUNWIND_EXPORT void _Unwind_Complete(_Unwind_Exception* exception_object) { + // This is to be called when exception handling completes to give us a chance + // to perform any housekeeping. EHABI #7.2. But we have nothing to do here. +} + +/// When _Unwind_RaiseException() is in phase2, it hands control +/// to the personality function at each frame. The personality +/// may force a jump to a landing pad in that function, the landing +/// pad code may then call _Unwind_Resume() to continue with the +/// unwinding. Note: the call to _Unwind_Resume() is from compiler +/// geneated user code. All other _Unwind_* routines are called +/// by the C++ runtime __cxa_* routines. +/// +/// Note: re-throwing an exception (as opposed to continuing the unwind) +/// is implemented by having the code call __cxa_rethrow() which +/// in turn calls _Unwind_Resume_or_Rethrow(). +_LIBUNWIND_EXPORT void +_Unwind_Resume(_Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)\n", exception_object); + unw_context_t uc; + unw_getcontext(&uc); + + // _Unwind_RaiseException on EHABI will always set the reserved1 field to 0, + // which is in the same position as private_1 below. + // TODO(ajwong): Who wronte the above? Why is it true? + unwind_phase2(&uc, exception_object, true); + + // Clients assume _Unwind_Resume() does not return, so all we can do is abort. + _LIBUNWIND_ABORT("_Unwind_Resume() can't return"); +} + +/// Called by personality handler during phase 2 to get LSDA for current frame. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { + unw_cursor_t *cursor = (unw_cursor_t *)context; + unw_proc_info_t frameInfo; + uintptr_t result = 0; + if (unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) + result = (uintptr_t)frameInfo.lsda; + _LIBUNWIND_TRACE_API("_Unwind_GetLanguageSpecificData(context=%p)" + "=> 0x%llx\n", context, (long long)result); + if (result != 0) { + if (*((uint8_t *)result) != 0xFF) + _LIBUNWIND_DEBUG_LOG("lsda at 0x%llx does not start with 0xFF\n", + (long long)result); + } + return result; +} + +static uint64_t ValueAsBitPattern(_Unwind_VRS_DataRepresentation representation, + void* valuep) { + uint64_t value = 0; + switch (representation) { + case _UVRSD_UINT32: + case _UVRSD_FLOAT: + memcpy(&value, valuep, sizeof(uint32_t)); + break; + + case _UVRSD_VFPX: + case _UVRSD_UINT64: + case _UVRSD_DOUBLE: + memcpy(&value, valuep, sizeof(uint64_t)); + break; + } + return value; +} + +_Unwind_VRS_Result _Unwind_VRS_Set( + _Unwind_Context *context, + _Unwind_VRS_RegClass regclass, + uint32_t regno, + _Unwind_VRS_DataRepresentation representation, + void *valuep) { + _LIBUNWIND_TRACE_API("_Unwind_VRS_Set(context=%p, regclass=%d, reg=%d, " + "rep=%d, value=0x%llX)\n", context, regclass, + regno, representation, + ValueAsBitPattern(representation, valuep)); + unw_cursor_t *cursor = (unw_cursor_t *)context; + switch (regclass) { + case _UVRSC_CORE: + if (representation != _UVRSD_UINT32 || regno > 15) + return _UVRSR_FAILED; + return unw_set_reg(cursor, UNW_ARM_R0 + regno, *(unw_word_t *)valuep) == + UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; + case _UVRSC_WMMXC: + if (representation != _UVRSD_UINT32 || regno > 3) + return _UVRSR_FAILED; + return unw_set_reg(cursor, UNW_ARM_WC0 + regno, *(unw_word_t *)valuep) == + UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; + case _UVRSC_VFP: + if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) + return _UVRSR_FAILED; + if (representation == _UVRSD_VFPX) { + // Can only touch d0-15 with FSTMFDX. + if (regno > 15) + return _UVRSR_FAILED; + unw_save_vfp_as_X(cursor); + } else { + if (regno > 31) + return _UVRSR_FAILED; + } + return unw_set_fpreg(cursor, UNW_ARM_D0 + regno, + *(unw_fpreg_t *)valuep) == UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; + case _UVRSC_WMMXD: + if (representation != _UVRSD_DOUBLE || regno > 31) + return _UVRSR_FAILED; + return unw_set_fpreg(cursor, UNW_ARM_WR0 + regno, + *(unw_fpreg_t *)valuep) == UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; + } +} + +static _Unwind_VRS_Result _Unwind_VRS_Get_Internal( + _Unwind_Context *context, + _Unwind_VRS_RegClass regclass, + uint32_t regno, + _Unwind_VRS_DataRepresentation representation, + void *valuep) { + unw_cursor_t *cursor = (unw_cursor_t *)context; + switch (regclass) { + case _UVRSC_CORE: + if (representation != _UVRSD_UINT32 || regno > 15) + return _UVRSR_FAILED; + return unw_get_reg(cursor, UNW_ARM_R0 + regno, (unw_word_t *)valuep) == + UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; + case _UVRSC_WMMXC: + if (representation != _UVRSD_UINT32 || regno > 3) + return _UVRSR_FAILED; + return unw_get_reg(cursor, UNW_ARM_WC0 + regno, (unw_word_t *)valuep) == + UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; + case _UVRSC_VFP: + if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) + return _UVRSR_FAILED; + if (representation == _UVRSD_VFPX) { + // Can only touch d0-15 with FSTMFDX. + if (regno > 15) + return _UVRSR_FAILED; + unw_save_vfp_as_X(cursor); + } else { + if (regno > 31) + return _UVRSR_FAILED; + } + return unw_get_fpreg(cursor, UNW_ARM_D0 + regno, (unw_fpreg_t *)valuep) == + UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; + case _UVRSC_WMMXD: + if (representation != _UVRSD_DOUBLE || regno > 31) + return _UVRSR_FAILED; + return unw_get_fpreg(cursor, UNW_ARM_WR0 + regno, + (unw_fpreg_t *)valuep) == UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; + } +} + +_Unwind_VRS_Result _Unwind_VRS_Get( + _Unwind_Context *context, + _Unwind_VRS_RegClass regclass, + uint32_t regno, + _Unwind_VRS_DataRepresentation representation, + void *valuep) { + _Unwind_VRS_Result result = + _Unwind_VRS_Get_Internal(context, regclass, regno, representation, + valuep); + _LIBUNWIND_TRACE_API("_Unwind_VRS_Get(context=%p, regclass=%d, reg=%d, " + "rep=%d, value=0x%llX, result = %d)\n", + context, regclass, regno, representation, + ValueAsBitPattern(representation, valuep), result); + return result; +} + +_Unwind_VRS_Result _Unwind_VRS_Pop( + _Unwind_Context *context, + _Unwind_VRS_RegClass regclass, + uint32_t discriminator, + _Unwind_VRS_DataRepresentation representation) { + _LIBUNWIND_TRACE_API("_Unwind_VRS_Pop(context=%p, regclass=%d, " + "discriminator=%d, representation=%d)\n", + context, regclass, discriminator, representation); + switch (regclass) { + case _UVRSC_CORE: + case _UVRSC_WMMXC: { + if (representation != _UVRSD_UINT32) + return _UVRSR_FAILED; + // When popping SP from the stack, we don't want to override it from the + // computed new stack location. See EHABI #7.5.4 table 3. + bool poppedSP = false; + uint32_t* sp; + if (_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, + _UVRSD_UINT32, &sp) != _UVRSR_OK) { + return _UVRSR_FAILED; + } + for (int i = 0; i < 16; ++i) { + if (!(discriminator & (1<<i))) + continue; + uint32_t value = *sp++; + if (regclass == _UVRSC_CORE && i == 13) + poppedSP = true; + if (_Unwind_VRS_Set(context, regclass, i, + _UVRSD_UINT32, &value) != _UVRSR_OK) { + return _UVRSR_FAILED; + } + } + if (!poppedSP) { + return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, + _UVRSD_UINT32, &sp); + } + return _UVRSR_OK; + } + case _UVRSC_VFP: + case _UVRSC_WMMXD: { + if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) + return _UVRSR_FAILED; + uint32_t first = discriminator >> 16; + uint32_t count = discriminator & 0xffff; + uint32_t end = first+count; + uint32_t* sp; + if (_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, + _UVRSD_UINT32, &sp) != _UVRSR_OK) { + return _UVRSR_FAILED; + } + // For _UVRSD_VFPX, we're assuming the data is stored in FSTMX "standard + // format 1", which is equivalent to FSTMD + a padding word. + for (uint32_t i = first; i < end; ++i) { + // SP is only 32-bit aligned so don't copy 64-bit at a time. + uint64_t value = *sp++; + value |= ((uint64_t)(*sp++)) << 32; + if (_Unwind_VRS_Set(context, regclass, i, representation, &value) != + _UVRSR_OK) + return _UVRSR_FAILED; + } + if (representation == _UVRSD_VFPX) + ++sp; + return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, + &sp); + } + }; +} + +/// Called by personality handler during phase 2 to find the start of the +/// function. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetRegionStart(struct _Unwind_Context *context) { + unw_cursor_t *cursor = (unw_cursor_t *)context; + unw_proc_info_t frameInfo; + uintptr_t result = 0; + if (unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) + result = (uintptr_t)frameInfo.start_ip; + _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%llX\n", + context, (long long)result); + return result; +} + + +/// Called by personality handler during phase 2 if a foreign exception +// is caught. +_LIBUNWIND_EXPORT void +_Unwind_DeleteException(_Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)\n", + exception_object); + if (exception_object->exception_cleanup != NULL) + (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, + exception_object); +} + +#endif // LIBCXXABI_ARM_EHABI diff --git a/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/Unwind/Unwind-arm.cpp b/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/Unwind/Unwind-arm.cpp deleted file mode 100644 index 83ce7f973..000000000 --- a/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/Unwind/Unwind-arm.cpp +++ /dev/null @@ -1,385 +0,0 @@ -//===--------------------------- Unwind-arm.c ----------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -// -// Implements ARM zero-cost C++ exceptions -// -//===----------------------------------------------------------------------===// - -#include <unwind.h> - -#include <stdbool.h> -#include <stdlib.h> - -#include "config.h" -#include "libunwind.h" -#include "../private_typeinfo.h" - - -#if LIBCXXABI_ARM_EHABI -namespace { - -// Strange order: take words in order, but inside word, take from most to least -// signinficant byte. -uint8_t getByte(uint32_t* data, size_t offset) { - uint8_t* byteData = reinterpret_cast<uint8_t*>(data); - return byteData[(offset & ~0x03) + (3 - (offset&0x03))]; -} - -const char* getNextWord(const char* data, uint32_t* out) { - *out = *reinterpret_cast<const uint32_t*>(data); - return data + 4; -} - -const char* getNextNibble(const char* data, uint32_t* out) { - *out = *reinterpret_cast<const uint16_t*>(data); - return data + 2; -} - -static inline uint32_t signExtendPrel31(uint32_t data) { - return data | ((data & 0x40000000u) << 1); -} - -struct Descriptor { - // See # 9.2 - typedef enum { - SU16 = 0, // Short descriptor, 16-bit entries - LU16 = 1, // Long descriptor, 16-bit entries - LU32 = 3, // Long descriptor, 32-bit entries - RESERVED0 = 4, RESERVED1 = 5, RESERVED2 = 6, RESERVED3 = 7, - RESERVED4 = 8, RESERVED5 = 9, RESERVED6 = 10, RESERVED7 = 11, - RESERVED8 = 12, RESERVED9 = 13, RESERVED10 = 14, RESERVED11 = 15 - } Format; - - // See # 9.2 - typedef enum { - CLEANUP = 0x0, - FUNC = 0x1, - CATCH = 0x2, - INVALID = 0x4 - } Kind; -}; - -_Unwind_Reason_Code ProcessDescriptors( - _Unwind_State state, - _Unwind_Control_Block* ucbp, - struct _Unwind_Context* context, - Descriptor::Format format, - const char* descriptorStart, - int flags) { - // EHT is inlined in the index using compact form. No descriptors. #5 - if (flags & 0x1) - return _URC_CONTINUE_UNWIND; - - const char* descriptor = descriptorStart; - uint32_t descriptorWord; - getNextWord(descriptor, &descriptorWord); - while (descriptorWord) { - // Read descriptor based on # 9.2. - uint32_t length; - uint32_t offset; - switch (format) { - case Descriptor::LU32: - descriptor = getNextWord(descriptor, &length); - descriptor = getNextWord(descriptor, &offset); - case Descriptor::LU16: - descriptor = getNextNibble(descriptor, &length); - descriptor = getNextNibble(descriptor, &offset); - default: - assert(false); - return _URC_FAILURE; - } - - // See # 9.2 table for decoding the kind of descriptor. It's a 2-bit value. - Descriptor::Kind kind = static_cast<Descriptor::Kind>((length & 0x1) | ((offset & 0x1) << 1)); - - // Clear off flag from last bit. - length &= ~1; - offset &= ~1; - uintptr_t scopeStart = ucbp->pr_cache.fnstart + offset; - uintptr_t scopeEnd = scopeStart + length; - uintptr_t pc = _Unwind_GetIP(context); - bool isInScope = (scopeStart <= pc) && (pc < scopeEnd); - - switch (kind) { - case Descriptor::CLEANUP: { - // TODO(ajwong): Handle cleanup descriptors. - break; - } - case Descriptor::FUNC: { - // TODO(ajwong): Handle function descriptors. - break; - } - case Descriptor::CATCH: { - // Catch descriptors require gobbling one more word. - uint32_t landing_pad; - descriptor = getNextWord(descriptor, &landing_pad); - - if (isInScope) { - // TODO(ajwong): This is only phase1 compatible logic. Implement - // phase2. - bool is_reference_type = landing_pad & 0x80000000; - landing_pad = signExtendPrel31(landing_pad & ~0x80000000); - if (landing_pad == 0xffffffff) { - return _URC_HANDLER_FOUND; - } else if (landing_pad == 0xfffffffe ) { - return _URC_FAILURE; - } else { - void* matched_object; - /* - if (__cxxabiv1::__cxa_type_match(ucbp, - reinterpret_cast<const std::type_info*>(landing_pad), - is_reference_type, &matched_object) != __cxxabiv1::ctm_failed) - return _URC_HANDLER_FOUND; - */ - _LIBUNWIND_ABORT("Type matching not implemented"); - } - } - break; - } - default: - _LIBUNWIND_ABORT("Invalid descriptor kind found."); - }; - - getNextWord(descriptor, &descriptorWord); - } - - return _URC_CONTINUE_UNWIND; -} - -_Unwind_Reason_Code unwindOneFrame( - _Unwind_State state, - _Unwind_Control_Block* ucbp, - struct _Unwind_Context* context) { - // Read the compact model EHT entry's header # 6.3 - uint32_t* unwindingData = ucbp->pr_cache.ehtp; - uint32_t unwindInfo = *unwindingData; - assert((unwindInfo & 0xf0000000) == 0x80000000 && "Must be a compact entry"); - Descriptor::Format format = static_cast<Descriptor::Format>((unwindInfo & 0x0f000000) >> 24); - size_t len = 0; - size_t startOffset = 0; - switch (format) { - case Descriptor::SU16: - len = 4; - startOffset = 1; - break; - case Descriptor::LU16: - case Descriptor::LU32: - len = 4 + 4 * ((unwindInfo & 0x00ff0000) >> 16); - startOffset = 2; - break; - default: - return _URC_FAILURE; - } - - // Handle descriptors before unwinding so they are processed in the context - // of the correct stack frame. - _Unwind_Reason_Code result = - ProcessDescriptors( - state, ucbp, context, format, - reinterpret_cast<const char*>(ucbp->pr_cache.ehtp) + len, - ucbp->pr_cache.additional); - - if (result != _URC_CONTINUE_UNWIND) - return result; - - return _Unwind_VRS_Interpret(context, unwindingData, startOffset, len); -} - -// Generates mask discriminator for _Unwind_VRS_Pop, e.g. for _UVRSC_CORE / -// _UVRSD_UINT32. -uint32_t RegisterMask(uint8_t start, uint8_t count_minus_one) { - return ((1U << (count_minus_one + 1)) - 1) << start; -} - -// Generates mask discriminator for _Unwind_VRS_Pop, e.g. for _UVRSC_VFP / -// _UVRSD_DOUBLE. -uint32_t RegisterRange(uint8_t start, uint8_t count_minus_one) { - return (start << 16) | (count_minus_one + 1); -} - -} // end anonymous namespace - -extern "C" _Unwind_Reason_Code _Unwind_VRS_Interpret( - _Unwind_Context* context, - uint32_t* data, - size_t offset, - size_t len) { - bool wrotePC = false; - bool finish = false; - while (offset < len && !finish) { - uint8_t byte = getByte(data, offset++); - if ((byte & 0x80) == 0) { - uint32_t sp; - _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp); - if (byte & 0x40) - sp -= ((byte & 0x3f) << 2) + 4; - else - sp += (byte << 2) + 4; - _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp); - } else { - switch (byte & 0xf0) { - case 0x80: { - if (offset >= len) - return _URC_FAILURE; - uint16_t registers = ((byte & 0x0f) << 12) | (getByte(data, offset++) << 4); - if (!registers) - return _URC_FAILURE; - if (registers & (1<<15)) - wrotePC = true; - _Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32); - break; - } - case 0x90: { - uint8_t reg = byte & 0x0f; - if (reg == 13 || reg == 15) - return _URC_FAILURE; - uint32_t sp; - _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_R0 + reg, - _UVRSD_UINT32, &sp); - _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, - &sp); - break; - } - case 0xa0: { - uint32_t registers = RegisterMask(4, byte & 0x07); - if (byte & 0x08) - registers |= 1<<14; - _Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32); - break; - } - case 0xb0: { - switch (byte) { - case 0xb0: - finish = true; - break; - case 0xb1: { - if (offset >= len) - return _URC_FAILURE; - uint8_t registers = getByte(data, offset++); - if (registers & 0xf0 || !registers) - return _URC_FAILURE; - _Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32); - break; - } - case 0xb2: { - uint32_t addend = 0; - uint32_t shift = 0; - // This decodes a uleb128 value. - while (true) { - if (offset >= len) - return _URC_FAILURE; - uint32_t v = getByte(data, offset++); - addend |= (v & 0x7f) << shift; - if ((v & 0x80) == 0) - break; - shift += 7; - } - uint32_t sp; - _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp); - sp += 0x204 + (addend << 2); - _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp); - break; - } - case 0xb3: { - uint8_t v = getByte(data, offset++); - _Unwind_VRS_Pop(context, _UVRSC_VFP, RegisterRange(v >> 4, v & 0x0f), _UVRSD_VFPX); - break; - } - case 0xb4: - case 0xb5: - case 0xb6: - case 0xb7: - return _URC_FAILURE; - default: - _Unwind_VRS_Pop(context, _UVRSC_VFP, RegisterRange(8, byte & 0x07), _UVRSD_VFPX); - break; - } - break; - } - case 0xc0: { - switch (byte) { - case 0xc0: - case 0xc1: - case 0xc2: - case 0xc3: - case 0xc4: - case 0xc5: - _Unwind_VRS_Pop(context, _UVRSC_WMMXD, RegisterRange(10, byte & 0x7), _UVRSD_DOUBLE); - break; - case 0xc6: { - uint8_t v = getByte(data, offset++); - uint8_t start = v >> 4; - uint8_t count_minus_one = v & 0xf; - if (start + count_minus_one >= 16) - return _URC_FAILURE; - _Unwind_VRS_Pop(context, _UVRSC_WMMXD, RegisterRange(start, count_minus_one), _UVRSD_DOUBLE); - break; - } - case 0xc7: { - uint8_t v = getByte(data, offset++); - if (!v || v & 0xf0) - return _URC_FAILURE; - _Unwind_VRS_Pop(context, _UVRSC_WMMXC, v, _UVRSD_DOUBLE); - break; - } - case 0xc8: - case 0xc9: { - uint8_t v = getByte(data, offset++); - uint8_t start = ((byte == 0xc8) ? 16 : 0) + (v >> 4); - uint8_t count_minus_one = v & 0xf; - if (start + count_minus_one >= 32) - return _URC_FAILURE; - _Unwind_VRS_Pop(context, _UVRSC_VFP, RegisterRange(start, count_minus_one), _UVRSD_DOUBLE); - break; - } - default: - return _URC_FAILURE; - } - break; - } - case 0xd0: { - if (byte & 0x08) - return _URC_FAILURE; - _Unwind_VRS_Pop(context, _UVRSC_VFP, RegisterRange(8, byte & 0x7), _UVRSD_DOUBLE); - break; - } - default: - return _URC_FAILURE; - } - } - } - if (!wrotePC) { - uint32_t lr; - _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_LR, _UVRSD_UINT32, &lr); - _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_IP, _UVRSD_UINT32, &lr); - } - return _URC_CONTINUE_UNWIND; -} - -extern "C" _Unwind_Reason_Code __aeabi_unwind_cpp_pr0( - _Unwind_State state, - _Unwind_Control_Block *ucbp, - _Unwind_Context *context) { - return unwindOneFrame(state, ucbp, context); -} - -extern "C" _Unwind_Reason_Code __aeabi_unwind_cpp_pr1( - _Unwind_State state, - _Unwind_Control_Block *ucbp, - _Unwind_Context *context) { - return unwindOneFrame(state, ucbp, context); -} - -extern "C" _Unwind_Reason_Code __aeabi_unwind_cpp_pr2( - _Unwind_State state, - _Unwind_Control_Block *ucbp, - _Unwind_Context *context) { - return unwindOneFrame(state, ucbp, context); -} - -#endif // LIBCXXABI_ARM_EHABI diff --git a/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/Unwind/UnwindCursor.hpp b/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/Unwind/UnwindCursor.hpp index c3490868f..d348b7887 100644 --- a/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/Unwind/UnwindCursor.hpp +++ b/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/Unwind/UnwindCursor.hpp @@ -498,7 +498,9 @@ private: } return false; } +#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND +#if _LIBUNWIND_SUPPORT_DWARF_UNWIND compact_unwind_encoding_t dwarfEncoding() const { R dummy; return dwarfEncoding(dummy); @@ -519,7 +521,7 @@ private: compact_unwind_encoding_t dwarfEncoding(Registers_arm64 &) const { return UNWIND_ARM64_MODE_DWARF; } -#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND +#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND A &_addressSpace; @@ -1272,6 +1274,9 @@ int UnwindCursor<A, R>::step() { result = this->stepWithDwarfFDE(); #elif LIBCXXABI_ARM_EHABI result = UNW_STEP_SUCCESS; +#elif defined(__i386__) || defined(__x86_64__) || defined(__mips__) || defined(__mips64) + // ToDo: really? + result = UNW_STEP_SUCCESS; #else #error Need _LIBUNWIND_SUPPORT_COMPACT_UNWIND or \ _LIBUNWIND_SUPPORT_DWARF_UNWIND or \ diff --git a/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/Unwind/UnwindLevel1.c b/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/Unwind/UnwindLevel1.c index aaf82d53a..410ac740a 100644 --- a/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/Unwind/UnwindLevel1.c +++ b/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/Unwind/UnwindLevel1.c @@ -22,16 +22,10 @@ #include "unwind.h" #include "config.h" -#if _LIBUNWIND_BUILD_ZERO_COST_APIS +#if _LIBUNWIND_BUILD_ZERO_COST_APIS && !LIBCXXABI_ARM_EHABI static _Unwind_Reason_Code unwind_phase1(unw_context_t *uc, _Unwind_Exception *exception_object) { - // EHABI #7.3 discusses preserving the VRS in a "temporary VRS" during - // phase 1 and then restoring it to the "primary VRS" for phase 2. The - // effect is phase 2 doesn't see any of the VRS manipulations from phase 1. - // In this implementation, the phases don't share the VRS backing store. - // Instead, they are passed the original |uc| and they create a new VRS - // from scratch thus achieving the same effect. unw_cursor_t cursor1; unw_init_local(&cursor1, uc); bool handlerNotFound; @@ -88,35 +82,16 @@ unwind_phase1(unw_context_t *uc, _Unwind_Exception *exception_object) { _LIBUNWIND_TRACE_UNWINDING( "unwind_phase1(ex_ojb=%p): calling personality function %p\n", exception_object, p); - struct _Unwind_Context *context = (struct _Unwind_Context *)(&cursor1); -#if LIBCXXABI_ARM_EHABI - exception_object->pr_cache.fnstart = frameInfo.start_ip; - exception_object->pr_cache.ehtp = (_Unwind_EHT_Header *)frameInfo.unwind_info; - exception_object->pr_cache.additional = frameInfo.flags; - _Unwind_Reason_Code personalityResult = - (*p)(_US_VIRTUAL_UNWIND_FRAME, exception_object, context); - _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): personality result %d " - "start_ip %x ehtp %p additional %x\n", - exception_object, personalityResult, - exception_object->pr_cache.fnstart, - exception_object->pr_cache.ehtp, - exception_object->pr_cache.additional); -#else // !LIBCXXABI_ARM_EHABI _Unwind_Reason_Code personalityResult = (*p)(1, _UA_SEARCH_PHASE, exception_object->exception_class, - exception_object, context); -#endif + exception_object, (struct _Unwind_Context *)(&cursor1)); switch (personalityResult) { case _URC_HANDLER_FOUND: // found a catch clause or locals that need destructing in this frame // stop search and remember stack pointer at the frame handlerNotFound = false; -#if LIBCXXABI_ARM_EHABI - // p should have initialized barrier_cache. EHABI #7.3.5 -#else unw_get_reg(&cursor1, UNW_REG_SP, &sp); exception_object->private_2 = (uintptr_t)sp; -#endif _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): " "_URC_HANDLER_FOUND \n", exception_object); @@ -129,12 +104,6 @@ unwind_phase1(unw_context_t *uc, _Unwind_Exception *exception_object) { // continue unwinding break; -#if LIBCXXABI_ARM_EHABI - // EHABI #7.3.3 - case _URC_FAILURE: - return _URC_FAILURE; -#endif - default: // something went wrong _LIBUNWIND_TRACE_UNWINDING( @@ -149,35 +118,16 @@ unwind_phase1(unw_context_t *uc, _Unwind_Exception *exception_object) { static _Unwind_Reason_Code -unwind_phase2(unw_context_t *uc, _Unwind_Exception *exception_object, bool resume) { - // See comment at the start of unwind_phase1 regarding VRS integrity. +unwind_phase2(unw_context_t *uc, _Unwind_Exception *exception_object) { unw_cursor_t cursor2; unw_init_local(&cursor2, uc); _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)\n", exception_object); - int frame_count = 0; // Walk each frame until we reach where search phase said to stop. while (true) { // Ask libuwind to get next frame (skip over first which is - // _Unwind_RaiseException or _Unwind_Resume). - // -#if LIBCXXABI_ARM_EHABI - // Resume only ever makes sense for 1 frame. - _Unwind_State state = - resume ? _US_UNWIND_FRAME_RESUME : _US_UNWIND_FRAME_STARTING; - if (resume && frame_count == 1) { - // On a resume, first unwind the _Unwind_Resume() frame. The next frame - // is now the landing pad for the cleanup from a previous execution of - // phase2. To continue unwindingly correctly, replace VRS[15] with the - // IP of the frame that the previous run of phase2 installed the context - // for. After this, continue unwinding as if normal. - // - // See #7.4.6 for details. - unw_set_reg(&cursor2, UNW_REG_IP, exception_object->unwinder_cache.reserved2); - resume = false; - } -#endif + // _Unwind_RaiseException). int stepResult = unw_step(&cursor2); if (stepResult == 0) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached " @@ -221,15 +171,6 @@ unwind_phase2(unw_context_t *uc, _Unwind_Exception *exception_object, bool resum if (frameInfo.handler != 0) { __personality_routine p = (__personality_routine)(long)(frameInfo.handler); - struct _Unwind_Context *context = (struct _Unwind_Context *)(&cursor2); -#if LIBCXXABI_ARM_EHABI - // EHABI #7.2 - exception_object->pr_cache.fnstart = frameInfo.start_ip; - exception_object->pr_cache.ehtp = (_Unwind_EHT_Header *)frameInfo.unwind_info; - exception_object->pr_cache.additional = frameInfo.flags; - _Unwind_Reason_Code personalityResult = - (*p)(state, exception_object, context); -#else _Unwind_Action action = _UA_CLEANUP_PHASE; if (sp == exception_object->private_2) { // Tell personality this was the frame it marked in phase 1. @@ -237,20 +178,14 @@ unwind_phase2(unw_context_t *uc, _Unwind_Exception *exception_object, bool resum } _Unwind_Reason_Code personalityResult = (*p)(1, action, exception_object->exception_class, exception_object, - context); -#endif + (struct _Unwind_Context *)(&cursor2)); switch (personalityResult) { case _URC_CONTINUE_UNWIND: // Continue unwinding _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", exception_object); -#if LIBCXXABI_ARM_EHABI - // EHABI #7.2 - if (sp == exception_object->barrier_cache.sp) { -#else if (sp == exception_object->private_2) { -#endif // Phase 1 said we would stop at this frame, but we did not... _LIBUNWIND_ABORT("during phase1 personality function said it would " "stop here, but now in phase2 it did not stop here"); @@ -272,23 +207,9 @@ unwind_phase2(unw_context_t *uc, _Unwind_Exception *exception_object, bool resum (long long)sp); } -#if LIBCXXABI_ARM_EHABI - { - // EHABI #7.4.1 says we need to preserve pc for when _Unwind_Resume - // is called back, to find this same frame. - unw_word_t pc; - unw_get_reg(&cursor2, UNW_REG_IP, &pc); - exception_object->unwinder_cache.reserved2 = (uint32_t)pc; - } -#endif unw_resume(&cursor2); // unw_resume() only returns if there was an error. return _URC_FATAL_PHASE2_ERROR; -#if LIBCXXABI_ARM_EHABI - // # EHABI #7.4.3 - case _URC_FAILURE: - abort(); -#endif default: // Personality routine returned an unknown result code. _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d", @@ -296,7 +217,6 @@ unwind_phase2(unw_context_t *uc, _Unwind_Exception *exception_object, bool resum return _URC_FATAL_PHASE2_ERROR; } } - frame_count++; } // Clean up phase did not resume at the frame that the search phase @@ -304,7 +224,6 @@ unwind_phase2(unw_context_t *uc, _Unwind_Exception *exception_object, bool resum return _URC_FATAL_PHASE2_ERROR; } -#if !LIBCXXABI_ARM_EHABI static _Unwind_Reason_Code unwind_phase2_forced(unw_context_t *uc, _Unwind_Exception *exception_object, @@ -404,7 +323,6 @@ unwind_phase2_forced(unw_context_t *uc, // would. return _URC_FATAL_PHASE2_ERROR; } -#endif /// Called by __cxa_throw. Only returns if there is a fatal error. @@ -415,16 +333,10 @@ _Unwind_RaiseException(_Unwind_Exception *exception_object) { unw_context_t uc; unw_getcontext(&uc); -#if LIBCXXABI_ARM_EHABI - // This field for is for compatibility with GCC to say this isn't a forced - // unwind. EHABI #7.2 - exception_object->unwinder_cache.reserved1 = 0; -#else // Mark that this is a non-forced unwind, so _Unwind_Resume() // can do the right thing. exception_object->private_1 = 0; exception_object->private_2 = 0; -#endif // phase 1: the search phase _Unwind_Reason_Code phase1 = unwind_phase1(&uc, exception_object); @@ -432,15 +344,10 @@ _Unwind_RaiseException(_Unwind_Exception *exception_object) { return phase1; // phase 2: the clean up phase - return unwind_phase2(&uc, exception_object, false); + return unwind_phase2(&uc, exception_object); } -#if LIBCXXABI_ARM_EHABI -_LIBUNWIND_EXPORT void _Unwind_Complete(_Unwind_Exception* exception_object) { - // This is to be called when exception handling completes to give us a chance - // to perform any housekeeping. EHABI #7.2. But we have nothing to do here. -} -#endif + /// When _Unwind_RaiseException() is in phase2, it hands control /// to the personality function at each frame. The personality @@ -459,19 +366,12 @@ _Unwind_Resume(_Unwind_Exception *exception_object) { unw_context_t uc; unw_getcontext(&uc); -#if LIBCXXABI_ARM_EHABI - // _Unwind_RaiseException on EHABI will always set the reserved1 field to 0, - // which is in the same position as private_1 below. - // TODO(ajwong): Who wronte the above? Why is it true? - unwind_phase2(&uc, exception_object, true); -#else if (exception_object->private_1 != 0) unwind_phase2_forced(&uc, exception_object, (_Unwind_Stop_Fn) exception_object->private_1, (void *)exception_object->private_2); else - unwind_phase2(&uc, exception_object, true); -#endif + unwind_phase2(&uc, exception_object); // Clients assume _Unwind_Resume() does not return, so all we can do is abort. _LIBUNWIND_ABORT("_Unwind_Resume() can't return"); @@ -479,7 +379,6 @@ _Unwind_Resume(_Unwind_Exception *exception_object) { -#if !LIBCXXABI_ARM_EHABI /// Not used by C++. /// Unwinds stack, calling "stop" function at each frame. /// Could be used to implement longjmp(). @@ -499,7 +398,6 @@ _Unwind_ForcedUnwind(_Unwind_Exception *exception_object, // do it return unwind_phase2_forced(&uc, exception_object, stop, stop_parameter); } -#endif // !LIBCXXABI_ARM_EHABI /// Called by personality handler during phase 2 to get LSDA for current frame. @@ -521,197 +419,6 @@ _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { } -#if LIBCXXABI_ARM_EHABI - -static uint64_t ValueAsBitPattern(_Unwind_VRS_DataRepresentation representation, - void* valuep) { - uint64_t value = 0; - switch (representation) { - case _UVRSD_UINT32: - case _UVRSD_FLOAT: - memcpy(&value, valuep, sizeof(uint32_t)); - break; - - case _UVRSD_VFPX: - case _UVRSD_UINT64: - case _UVRSD_DOUBLE: - memcpy(&value, valuep, sizeof(uint64_t)); - break; - } - return value; -} - -_Unwind_VRS_Result _Unwind_VRS_Set( - _Unwind_Context *context, - _Unwind_VRS_RegClass regclass, - uint32_t regno, - _Unwind_VRS_DataRepresentation representation, - void *valuep) { - _LIBUNWIND_TRACE_API("_Unwind_VRS_Set(context=%p, regclass=%d, reg=%d, " - "rep=%d, value=0x%llX)\n", context, regclass, - regno, representation, - ValueAsBitPattern(representation, valuep)); - unw_cursor_t *cursor = (unw_cursor_t *)context; - switch (regclass) { - case _UVRSC_CORE: - if (representation != _UVRSD_UINT32 || regno > 15) - return _UVRSR_FAILED; - return unw_set_reg(cursor, UNW_ARM_R0 + regno, *(unw_word_t*)valuep) == UNW_ESUCCESS ? - _UVRSR_OK : _UVRSR_FAILED; - case _UVRSC_WMMXC: - if (representation != _UVRSD_UINT32 || regno > 3) - return _UVRSR_FAILED; - return unw_set_reg(cursor, UNW_ARM_WC0 + regno, *(unw_word_t*)valuep) == UNW_ESUCCESS ? - _UVRSR_OK : _UVRSR_FAILED; - case _UVRSC_VFP: - if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) - return _UVRSR_FAILED; - if (representation == _UVRSD_VFPX) { - // Can only touch d0-15 with FSTMFDX. - if (regno > 15) - return _UVRSR_FAILED; - unw_save_vfp_as_X(cursor); - } else { - if (regno > 31) - return _UVRSR_FAILED; - } - return unw_set_fpreg(cursor, UNW_ARM_D0 + regno, *(unw_fpreg_t*)valuep) == UNW_ESUCCESS ? - _UVRSR_OK : _UVRSR_FAILED; - case _UVRSC_WMMXD: - if (representation != _UVRSD_DOUBLE || regno > 31) - return _UVRSR_FAILED; - return unw_set_fpreg(cursor, UNW_ARM_WR0 + regno, *(unw_fpreg_t*)valuep) == UNW_ESUCCESS ? - _UVRSR_OK : _UVRSR_FAILED; - } -} - -static _Unwind_VRS_Result _Unwind_VRS_Get_Internal( - _Unwind_Context *context, - _Unwind_VRS_RegClass regclass, - uint32_t regno, - _Unwind_VRS_DataRepresentation representation, - void *valuep) { - unw_cursor_t *cursor = (unw_cursor_t *)context; - switch (regclass) { - case _UVRSC_CORE: - if (representation != _UVRSD_UINT32 || regno > 15) - return _UVRSR_FAILED; - return unw_get_reg(cursor, UNW_ARM_R0 + regno, (unw_word_t*)valuep) == UNW_ESUCCESS ? - _UVRSR_OK : _UVRSR_FAILED; - case _UVRSC_WMMXC: - if (representation != _UVRSD_UINT32 || regno > 3) - return _UVRSR_FAILED; - return unw_get_reg(cursor, UNW_ARM_WC0 + regno, (unw_word_t*)valuep) == UNW_ESUCCESS ? - _UVRSR_OK : _UVRSR_FAILED; - case _UVRSC_VFP: - if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) - return _UVRSR_FAILED; - if (representation == _UVRSD_VFPX) { - // Can only touch d0-15 with FSTMFDX. - if (regno > 15) - return _UVRSR_FAILED; - unw_save_vfp_as_X(cursor); - } else { - if (regno > 31) - return _UVRSR_FAILED; - } - return unw_get_fpreg(cursor, UNW_ARM_D0 + regno, (unw_fpreg_t*)valuep) == UNW_ESUCCESS ? - _UVRSR_OK : _UVRSR_FAILED; - case _UVRSC_WMMXD: - if (representation != _UVRSD_DOUBLE || regno > 31) - return _UVRSR_FAILED; - return unw_get_fpreg(cursor, UNW_ARM_WR0 + regno, (unw_fpreg_t*)valuep) == UNW_ESUCCESS ? - _UVRSR_OK : _UVRSR_FAILED; - } -} - -_Unwind_VRS_Result _Unwind_VRS_Get( - _Unwind_Context *context, - _Unwind_VRS_RegClass regclass, - uint32_t regno, - _Unwind_VRS_DataRepresentation representation, - void *valuep) { - _Unwind_VRS_Result result = - _Unwind_VRS_Get_Internal(context, regclass, regno, representation, - valuep); - _LIBUNWIND_TRACE_API("_Unwind_VRS_Get(context=%p, regclass=%d, reg=%d, " - "rep=%d, value=0x%llX, result = %d)\n", context, regclass, - regno, representation, - ValueAsBitPattern(representation, valuep), result); - return result; -} - -_Unwind_VRS_Result _Unwind_VRS_Pop( - _Unwind_Context *context, - _Unwind_VRS_RegClass regclass, - uint32_t discriminator, - _Unwind_VRS_DataRepresentation representation) { - _LIBUNWIND_TRACE_API("_Unwind_VRS_Pop(context=%p, regclass=%d, " - "discriminator=%d, representation=%d)\n", - context, regclass, discriminator, representation); - switch (regclass) { - case _UVRSC_CORE: - case _UVRSC_WMMXC: { - if (representation != _UVRSD_UINT32) - return _UVRSR_FAILED; - // When popping SP from the stack, we don't want to override it from the - // computed new stack location. See EHABI #7.5.4 table 3. - bool poppedSP = false; - uint32_t* sp; - if (_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, - _UVRSD_UINT32, &sp) != _UVRSR_OK) { - return _UVRSR_FAILED; - } - int i; - for (i = 0; i < 16; ++i) { - if (!(discriminator & (1<<i))) - continue; - uint32_t value = *sp++; - if (regclass == _UVRSC_CORE && i == 13) - poppedSP = true; - if (_Unwind_VRS_Set(context, regclass, i, - _UVRSD_UINT32, &value) != _UVRSR_OK) { - return _UVRSR_FAILED; - } - } - if (!poppedSP) { - return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, - _UVRSD_UINT32, &sp); - } - return _UVRSR_OK; - } - case _UVRSC_VFP: - case _UVRSC_WMMXD: { - if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) - return _UVRSR_FAILED; - uint32_t first = discriminator >> 16; - uint32_t count = discriminator & 0xffff; - uint32_t end = first+count; - uint32_t* sp; - if (_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, - _UVRSD_UINT32, &sp) != _UVRSR_OK) { - return _UVRSR_FAILED; - } - // For _UVRSD_VFPX, we're assuming the data is stored in FSTMX "standard - // format 1", which is equivalent to FSTMD + a padding word. - uint32_t i; - for (i = first; i < end; ++i) { - // SP is only 32-bit aligned so don't copy 64-bit at a time. - uint64_t value = *sp++; - value |= ((uint64_t)(*sp++)) << 32; - if (_Unwind_VRS_Set(context, regclass, i, representation, &value) != _UVRSR_OK) - return _UVRSR_FAILED; - } - if (representation == _UVRSD_VFPX) - ++sp; - return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp); - } - }; -} - -#else // !LIBCXXABI_ARM_EHABI - -// ARM EHABI provides these as inline wrappers in the public header. /// Called by personality handler during phase 2 to get register values. _LIBUNWIND_EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, @@ -762,7 +469,6 @@ _LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context, unw_set_reg(cursor, UNW_REG_IP, new_value); } -#endif // !LICXXABI_ARM_EHABI /// Called by personality handler during phase 2 to find the start of the /// function. @@ -790,4 +496,4 @@ _Unwind_DeleteException(_Unwind_Exception *exception_object) { exception_object); } -#endif // _LIBUNWIND_BUILD_ZERO_COST_APIS +#endif // _LIBUNWIND_BUILD_ZERO_COST_APIS && !LIBCXXABI_ARM_EHABI diff --git a/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/Unwind/UnwindRegistersSave.S b/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/Unwind/UnwindRegistersSave.S index d36e84c59..48c45b00e 100644 --- a/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/Unwind/UnwindRegistersSave.S +++ b/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/Unwind/UnwindRegistersSave.S @@ -238,47 +238,47 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) ; On entry: ; thread_state pointer is in x0 ; - ; skip restore of x0,x1 for now - ldp x2, x3, [x0, #0x010] - ldp x4, x5, [x0, #0x020] - ldp x6, x7, [x0, #0x030] - ldp x8, x9, [x0, #0x040] - ldp x10,x11, [x0, #0x050] - ldp x12,x13, [x0, #0x060] - ldp x14,x15, [x0, #0x070] - ldp x16,x17, [x0, #0x080] - ldp x18,x19, [x0, #0x090] - ldp x20,x21, [x0, #0x0A0] - ldp x22,x23, [x0, #0x0B0] - ldp x24,x25, [x0, #0x0C0] - ldp x26,x27, [x0, #0x0D0] - ldp x28,fp, [x0, #0x0E0] - ldr lr, [x0, #0x100] ; restore pc into lr - ldr x1, [x0, #0x0F8] - mov sp,x1 ; restore sp - - ldp d0, d1, [x0, #0x110] - ldp d2, d3, [x0, #0x120] - ldp d4, d5, [x0, #0x130] - ldp d6, d7, [x0, #0x140] - ldp d8, d9, [x0, #0x150] - ldp d10,d11, [x0, #0x160] - ldp d12,d13, [x0, #0x170] - ldp d14,d15, [x0, #0x180] - ldp d16,d17, [x0, #0x190] - ldp d18,d19, [x0, #0x1A0] - ldp d20,d21, [x0, #0x1B0] - ldp d22,d23, [x0, #0x1C0] - ldp d24,d25, [x0, #0x1D0] - ldp d26,d27, [x0, #0x1E0] - ldp d28,d29, [x0, #0x1F0] - ldr d30, [x0, #0x200] - ldr d31, [x0, #0x208] - - ldp x0, x1, [x0, #0x000] ; restore x0,x1 - ret lr ; jump to pc - - + .p2align 2 +DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) + stp x0, x1, [x0, #0x000] + stp x2, x3, [x0, #0x010] + stp x4, x5, [x0, #0x020] + stp x6, x7, [x0, #0x030] + stp x8, x9, [x0, #0x040] + stp x10,x11, [x0, #0x050] + stp x12,x13, [x0, #0x060] + stp x14,x15, [x0, #0x070] + stp x16,x17, [x0, #0x080] + stp x18,x19, [x0, #0x090] + stp x20,x21, [x0, #0x0A0] + stp x22,x23, [x0, #0x0B0] + stp x24,x25, [x0, #0x0C0] + stp x26,x27, [x0, #0x0D0] + stp x28,fp, [x0, #0x0E0] + str lr, [x0, #0x0F0] + mov x1,sp + str x1, [x0, #0x0F8] + str lr, [x0, #0x100] ; store return address as pc + ; skip cpsr + stp d0, d1, [x0, #0x110] + stp d2, d3, [x0, #0x120] + stp d4, d5, [x0, #0x130] + stp d6, d7, [x0, #0x140] + stp d8, d9, [x0, #0x150] + stp d10,d11, [x0, #0x160] + stp d12,d13, [x0, #0x170] + stp d14,d15, [x0, #0x180] + stp d16,d17, [x0, #0x190] + stp d18,d19, [x0, #0x1A0] + stp d20,d21, [x0, #0x1B0] + stp d22,d23, [x0, #0x1C0] + stp d24,d25, [x0, #0x1D0] + stp d26,d27, [x0, #0x1E0] + stp d28,d29, [x0, #0x1F0] + str d30, [x0, #0x200] + str d31, [x0, #0x208] + ldr x0, #0 ; return UNW_ESUCCESS + ret #elif __arm__ && !__APPLE__ @@ -390,4 +390,20 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveiWMMXControl stc2 p1, cr11, [r0], #4 @ wstrw wCGR3, [r0], #4 mov pc, lr +#elif __mips64 +# +# extern int unw_getcontext(unw_context_t* thread_state) +# ToDo: +# +DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) + j $31 + +#elif __mips__ +# +# extern int unw_getcontext(unw_context_t* thread_state) +# ToDo: +# +DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) + j $31 + #endif diff --git a/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/Unwind/config.h b/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/Unwind/config.h index 0d15d7189..ebd600f78 100644 --- a/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/Unwind/config.h +++ b/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/Unwind/config.h @@ -72,7 +72,7 @@ assert(false); abort(); } - #define _LIBUNWIND_BUILD_ZERO_COST_APIS (__i386__ || __x86_64__ || __arm64__ || __arm__) + #define _LIBUNWIND_BUILD_ZERO_COST_APIS (__i386__ || __x86_64__ || __arm64__ || __arm__ || __mips__) #define _LIBUNWIND_BUILD_SJLJ_APIS 0 #define _LIBUNWIND_SUPPORT_FRAME_APIS (__i386__ || __x86_64__) #define _LIBUNWIND_EXPORT __attribute__((visibility("default"))) @@ -81,7 +81,7 @@ #define _LIBUNWIND_ABORT(msg) assert_rtn(__func__, __FILE__, __LINE__, msg) #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 0 - #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 0 + #define _LIBUNWIND_SUPPORT_DWARF_UNWIND defined(__mips__) #define _LIBUNWIND_SUPPORT_DWARF_INDEX 0 #define _LIBUNWIND_IS_BAREMETAL 0 #endif diff --git a/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/cxa_personality.cpp b/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/cxa_personality.cpp index ec50619b1..6a1857663 100644 --- a/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/cxa_personality.cpp +++ b/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/cxa_personality.cpp @@ -977,7 +977,7 @@ __gxx_personality_v0 { // No, do the scan again to reload the results. scan_eh_tab(results, actions, native_exception, unwind_exception, context, - (const uint8_t*)_Unwind_GetLanguageSpecificData(context)); + (const uint8_t*)_Unwind_GetLanguageSpecificData(context)); // Phase 1 told us we would find a handler. Now in Phase 2 we // didn't find a handler. The eh table should not be changing! if (results.reason != _URC_HANDLER_FOUND) diff --git a/sources/cxx-stl/llvm-libc++abi/sources.mk b/sources/cxx-stl/llvm-libc++abi/sources.mk index 59e5d4e52..5a460f09b 100644 --- a/sources/cxx-stl/llvm-libc++abi/sources.mk +++ b/sources/cxx-stl/llvm-libc++abi/sources.mk @@ -19,7 +19,7 @@ libcxxabi_src_files := \ libcxxabi/src/stdexcept.cpp \ libcxxabi/src/typeinfo.cpp \ libcxxabi/src/Unwind/libunwind.cpp \ - libcxxabi/src/Unwind/Unwind-arm.cpp \ + libcxxabi/src/Unwind/Unwind-EHABI.cpp \ libcxxabi/src/Unwind/UnwindLevel1.c \ libcxxabi/src/Unwind/UnwindLevel1-gcc-ext.c \ libcxxabi/src/Unwind/UnwindRegistersRestore.S \ |