From: Pat Gavlin Date: Sat, 21 Feb 2015 00:41:27 +0000 (-0800) Subject: Merge pull request #313 from pgavlin/LibUnwindCheck X-Git-Tag: accepted/tizen/base/20180629.140029~7080 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ec30947b1d83c31ea5d14351c491745516b7958b;p=platform%2Fupstream%2Fcoreclr.git Merge pull request #313 from pgavlin/LibUnwindCheck Move the error that is emitted when libunwind is missing into CMake. --- ec30947b1d83c31ea5d14351c491745516b7958b diff --cc src/pal/src/exception/seh-unwind.cpp index be82693,da4bed6..a6c038a --- a/src/pal/src/exception/seh-unwind.cpp +++ b/src/pal/src/exception/seh-unwind.cpp @@@ -160,13 -199,299 +160,9 @@@ BOOL PAL_VirtualUnwind(CONTEXT *context return TRUE; } #else - #if __LINUX__ - #error Cannot find libuwind. Try installing libunwind8 and libunwind8-dev - #else #error don't know how to unwind on this platform #endif - #endif -#if _DEBUG -//---------------------------------------------------------------------- -// Virtual Unwinding Debugging Assertions -//---------------------------------------------------------------------- - -// Print a trace of virtually unwinding the stack. -// This helps us diagnose non-unwindable stacks. -// Unfortunately, calling this function from gdb will not be very useful, -// since gdb makes it look like it had been called directly from "start" -// (whose unwind info says we reached the end of the stack). -// You can still call it from, say, RaiseTheExceptionInternalOnly. - -// (non-static to ease debugging) -void DisplayContext(_Unwind_Context *context) -{ - fprintf(stderr, " ip =%p", _Unwind_GetIP(context)); - fprintf(stderr, " cfa=%p", _Unwind_GetCFA(context)); -#if defined(_X86_) - // TODO: display more registers -#endif - fprintf(stderr, "\n"); -} - -static _Unwind_Reason_Code PrintVirtualUnwindCallback(_Unwind_Context *context, void *pvParam) -{ - int *pFrameNumber = (int *) pvParam; - - void *ip = _Unwind_GetIP(context); - const char *module = NULL; - const char *name = 0; - int offset = 0; - - Dl_info dl_info; - if (dladdr(ip, &dl_info)) - { - module = dl_info.dli_fname; - if (dl_info.dli_sname) - { - name = dl_info.dli_sname; - offset = (char *) ip - (char *) dl_info.dli_saddr; - } - else - { - name = ""; - offset = (char *) ip - (char *) dl_info.dli_fbase; - } - } - - if (module) - fprintf(stderr, "#%-3d %s!%s+%d\n", *pFrameNumber, module, name, offset); - else - fprintf(stderr, "#%-3d ??\n", *pFrameNumber); - DisplayContext(context); - (*pFrameNumber)++; - return _URC_NO_REASON; -} - -extern "C" void PAL_PrintVirtualUnwind() -{ - BOOL fEntered = PAL_ReenterForEH(); - - fprintf(stderr, "\nVirtual unwind of PAL thread %p\n", InternalGetCurrentThread()); - int frameNumber = 0; - _Unwind_Reason_Code urc = _Unwind_Backtrace(PrintVirtualUnwindCallback, &frameNumber); - fprintf(stderr, "End of stack (return code=%d).\n", urc); - - if (fEntered) - { - PAL_Leave(PAL_BoundaryEH); - } -} - -static const char *PAL_CHECK_UNWINDABLE_STACKS = "PAL_CheckUnwindableStacks"; - -enum CheckUnwindableStacksMode -{ - // special value to indicate we've not initialized yet - CheckUnwindableStacks_Uninitialized = -1, - - CheckUnwindableStacks_Off = 0, - CheckUnwindableStacks_On = 1, - CheckUnwindableStacks_Thorough = 2, - - CheckUnwindableStacks_Default = CheckUnwindableStacks_On -}; - -static CheckUnwindableStacksMode s_mode = CheckUnwindableStacks_Uninitialized; - -// A variant of the above. This one's not meant for CLR developers to use for tracing, -// but implements debug checks to assert stack consistency. -static _Unwind_Reason_Code CheckVirtualUnwindCallback(_Unwind_Context *context, void *pvParam) -{ - void *ip = _Unwind_GetIP(context); - - // If we reach an IP that we cannot find a module for, - // then we ended up in dynamically-generated code and - // the stack will not be unwindable past this point. - Dl_info dl_info; - if (dladdr(ip, &dl_info) == 0 || - ((s_mode == CheckUnwindableStacks_Thorough) && - ( dl_info.dli_sname == NULL || - ( _Unwind_Find_FDE(ip, NULL) == NULL && - strcmp(dl_info.dli_sname, "start") && - strcmp(dl_info.dli_sname, "_thread_create_running"))))) - { - *(BOOL *) pvParam = FALSE; - } - - return _URC_NO_REASON; -} - -extern "C" void PAL_CheckVirtualUnwind() -{ - if (s_mode == CheckUnwindableStacks_Uninitialized) - { - const char *checkUnwindableStacks = getenv(PAL_CHECK_UNWINDABLE_STACKS); - s_mode = checkUnwindableStacks ? - (CheckUnwindableStacksMode) atoi(checkUnwindableStacks) : CheckUnwindableStacks_Default; - } - - if (s_mode != CheckUnwindableStacks_Off) - { - BOOL fUnwindable = TRUE; - _ASSERTE(_Unwind_Backtrace(CheckVirtualUnwindCallback, &fUnwindable) == _URC_END_OF_STACK); - if (!fUnwindable) - { - PAL_PrintVirtualUnwind(); - ASSERT("Stack not unwindable. Throwing may terminate the process.\n"); - } - } -} -#endif // _DEBUG - -//---------------------------------------------------------------------- -// Registering Vectored Handlers -//---------------------------------------------------------------------- - -static PVECTORED_EXCEPTION_HANDLER VectoredExceptionHandler = NULL; -static PVECTORED_EXCEPTION_HANDLER VectoredContinueHandler = NULL; - -void SetVectoredExceptionHandler(PVECTORED_EXCEPTION_HANDLER pHandler) -{ - PERF_ENTRY(SetVectoredExceptionHandler); - ENTRY("SetVectoredExceptionHandler(pHandler=%p)\n", pHandler); - - _ASSERTE(VectoredExceptionHandler == NULL); - VectoredExceptionHandler = pHandler; - - LOGEXIT("SetVectoredExceptionHandler returns\n"); - PERF_EXIT(SetVectoredExceptionHandler); - -} - -void SetVectoredContinueHandler(PVECTORED_EXCEPTION_HANDLER pHandler) -{ - PERF_ENTRY(SetVectoredContinueHandler); - ENTRY("SetVectoredContinueHandler(pHandler=%p)\n", pHandler); - - _ASSERTE(VectoredContinueHandler == NULL); - VectoredContinueHandler = pHandler; - - LOGEXIT("SetVectoredContinueHandler returns\n"); - PERF_EXIT(SetVectoredContinueHandler); -} - -//---------------------------------------------------------------------- -// Representation of an SEH Exception as a C++ object -//---------------------------------------------------------------------- - -struct PAL_SEHException -{ -public: - // Note that the following two are actually embedded in this heap-allocated - // instance - in contrast to Win32, where the exception record would usually - // be allocated on the stack. This is needed because foreign cleanup handlers - // partially unwind the stack on the second pass. - EXCEPTION_POINTERS ExceptionPointers; - EXCEPTION_RECORD ExceptionRecord; - CONTEXT ContextRecord; - - PAL_SEHException(EXCEPTION_RECORD *pExceptionRecord, CONTEXT *pContextRecord) - { - ExceptionPointers.ExceptionRecord = &ExceptionRecord; - ExceptionPointers.ContextRecord = &ContextRecord; - ExceptionRecord = *pExceptionRecord; - ContextRecord = *pContextRecord; - nestedExceptionEstablisherFrame = NULL; - } - - static PAL_SEHException *FromExceptionObject(_Unwind_Exception *exceptionObject) - { - if (exceptionObject->exception_class == Class) - { - if (*((__cxa_exception *) (exceptionObject + 1) - 1)->exceptionType == typeid(PAL_SEHException)) - { - return (PAL_SEHException *) (exceptionObject + 1); - } - } - return NULL; - } - - void NestedIn(_Unwind_Context *context) - { - nestedExceptionEstablisherFrame = _Unwind_GetCFA(context); - ExceptionRecord.ExceptionFlags |= EXCEPTION_NESTED_CALL; - } - - void RanThroughFilter(_Unwind_Context *context) - { - if (nestedExceptionEstablisherFrame == _Unwind_GetCFA(context)) - { - // We were processing a nested exception, and we have repeated - // the search phase past the filter that threw the nested exception. - // Thus, clear the corresponding flag now. - ExceptionRecord.ExceptionFlags &= ~EXCEPTION_NESTED_CALL; - } - } - -private: -#ifdef __GNUC__ - static const __uint64_t Class = 0x474e5543432b2b00ULL; // vendor = GNUC, language = C++\0 -#else -#error Vendor code not defined for this platform. -#endif - - // If we encountered a nested exception, the EXCEPTION_NESTED_CALL flag must - // remain set on the exception while unwinding to the frame with the CFA - // stored below. Note that this will always be a PAL_TryExcept frame. - void *nestedExceptionEstablisherFrame; -}; - -EXCEPTION_POINTERS * -PALAPI -PAL_GetExceptionPointers(_Unwind_Exception *exceptionObject) -{ - PAL_SEHException *pSEHException = PAL_SEHException::FromExceptionObject(exceptionObject); - if (pSEHException) - { - return &pSEHException->ExceptionPointers; - } - return NULL; -} - -//---------------------------------------------------------------------- -// Raising Exceptions -//---------------------------------------------------------------------- - -static void DeleteThrownException(_Unwind_Exception *exceptionObject) -{ - // The argument exception has been thrown. - _ASSERTE(std::uncaught_exception()); - - // Deleting it in this way will adjust the uncaught exceptions count. - __cxa_begin_catch(exceptionObject); - __cxa_end_catch(); -} - -static void RunVectoredHandler(EXCEPTION_POINTERS *pExceptionPointers, _Unwind_Exception *exceptionObject, PVECTORED_EXCEPTION_HANDLER pHandler) -{ - if (pHandler != NULL) - { - EXCEPTION_DISPOSITION disposition = pHandler(pExceptionPointers); - switch (disposition) - { - case EXCEPTION_CONTINUE_EXECUTION: - { - BOOL fNonContinuable = pExceptionPointers->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE; - CONTEXT *context = pExceptionPointers->ContextRecord; - if (fNonContinuable) - { - RaiseException(EXCEPTION_NONCONTINUABLE_EXCEPTION, - EXCEPTION_NONCONTINUABLE, 0, NULL); - } - else - { - SetThreadContext(PAL_GetCurrentThread(), context); - } - } - abort(); // should never reach here - case EXCEPTION_CONTINUE_SEARCH: - break; - default: - DeleteThrownException(exceptionObject); - RaiseException(EXCEPTION_INVALID_DISPOSITION, - EXCEPTION_NONCONTINUABLE, 0, NULL); - abort(); // should never reach here - } - } -} - PAL_NORETURN static void RtlpRaiseException(EXCEPTION_RECORD *ExceptionRecord) {