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 = "<img-base>";
- 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)
{