blob: a7fa505024b2c020ae4e7bf2f7bfe7fc6f17ac54 [file] [log] [blame]
/**
* This file has no copyright assigned and is placed in the Public Domain.
* This file is part of the mingw-w64 runtime package.
* No warranty is given; refer to the file DISCLAIMER.PD within this package.
*/
#include <corecrt.h>
#include <windows.h>
#if defined(__i386__)
DECLSPEC_NOINLINE /* decrease chance of modifying caller's registers and/or stack frame */
#endif
static BOOL is_fastfail_available(void)
{
#if defined(__i386__)
HMODULE module = GetModuleHandleA("kernel32.dll");
BOOL (WINAPI *func)(DWORD) = module ? (LPVOID)GetProcAddress(module, "IsProcessorFeaturePresent") : (LPVOID)NULL;
return func ? func(PF_FASTFAIL_AVAILABLE) : FALSE;
#elif defined(__x86_64__)
return IsProcessorFeaturePresent(PF_FASTFAIL_AVAILABLE);
#elif defined (__arm__) || defined(__aarch64__)
/* On ARM is fastfail always available */
return TRUE;
#else
#error Unsupported platform
#endif
}
/* DECLSPEC_NOINLINE is needed for __builtin_return_address() and __builtin_frame_address() usage */
DECLSPEC_NOINLINE __MINGW_ATTRIB_NORETURN void __cdecl _invoke_watson(const wchar_t * __UNUSED_PARAM(expression), const wchar_t * __UNUSED_PARAM(function_name), const wchar_t * __UNUSED_PARAM(file_name), unsigned int __UNUSED_PARAM(line_number), uintptr_t __UNUSED_PARAM(reserved))
{
EXCEPTION_RECORD exception_record = { 0, };
CONTEXT context = { 0, };
EXCEPTION_POINTERS exception_pointers = { &exception_record, &context };
#if defined(__x86_64__)
ULONG64 establisher_frame;
ULONG64 image_base;
PRUNTIME_FUNCTION function_entry;
PVOID handler_data;
#endif
if (is_fastfail_available())
__fastfail(FAST_FAIL_INVALID_ARG);
/*
* RtlCaptureContext() is available since Windows XP.
* UCRT runtime uses inline assemly on 32-bit x86.
* For compatibility with UCRT do same thing.
*/
#if defined(__i386__)
asm volatile(
"mov %%eax, %0\n\t"
"mov %%ecx, %1\n\t"
"mov %%edx, %2\n\t"
"mov %%ebx, %3\n\t"
"mov %%esi, %4\n\t"
"mov %%edi, %5\n\t"
"movw %%ss, %w6\n\t"
"movw %%cs, %w7\n\t"
"movw %%ds, %w8\n\t"
"movw %%es, %w9\n\t"
"movw %%fs, %w10\n\t"
"movw %%gs, %w11\n\t"
"pushf\n\t"
"pop %12"
:
/* Specify only "m" (memory) to prevent using registers and clobbering their content. */
"=m" (context.Eax), "=m" (context.Ecx), "=m" (context.Edx),
"=m" (context.Ebx), "=m" (context.Esi), "=m" (context.Edi),
"=m" (context.SegSs), "=m" (context.SegCs), "=m" (context.SegDs),
"=m" (context.SegEs), "=m" (context.SegFs), "=m" (context.SegGs),
"=m" (context.EFlags)
:
:
);
#else
RtlCaptureContext(&context);
#endif
/* Fill additional platform specific fields of the parent (caller) function into context. */
#if defined(__i386__)
context.ContextFlags = CONTEXT_CONTROL;
context.Eip = (uintptr_t)__builtin_extract_return_addr(__builtin_return_address(0)); /* msvc uses _ReturnAddress() */
context.Esp = (uintptr_t)__builtin_frame_address(0); /* msvc uses _AddressOfReturnAddress() */
context.Ebp = *((uintptr_t *)__builtin_frame_address(0)-1); /* msvc uses *((ULONG *)_AddressOfReturnAddress()-1) */
#elif defined(__x86_64__)
function_entry = RtlLookupFunctionEntry(context.Rip, &image_base, NULL);
if (function_entry)
RtlVirtualUnwind(UNW_FLAG_NHANDLER, image_base, context.Rip, function_entry, &context, &handler_data, &establisher_frame, NULL);
context.Rip = (uintptr_t)__builtin_extract_return_addr(__builtin_return_address(0)); /* msvc uses _ReturnAddress() */
context.Rsp = (uintptr_t)__builtin_frame_address(0); /* msvc uses _AddressOfReturnAddress()+8 */
context.Rbp = *((uintptr_t *)__builtin_frame_address(0)-1); /* not filled filled by msvc */
#endif
exception_record.ExceptionCode = STATUS_INVALID_CRUNTIME_PARAMETER;
exception_record.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
exception_record.ExceptionAddress = __builtin_extract_return_addr(__builtin_return_address(0)); /* msvc uses _ReturnAddress() */
/* Remove all filters, trigger exception and terminate the process. */
SetUnhandledExceptionFilter(NULL);
UnhandledExceptionFilter(&exception_pointers);
TerminateProcess(GetCurrentProcess(), STATUS_INVALID_CRUNTIME_PARAMETER);
__builtin_unreachable();
}
__MINGW_ATTRIB_NORETURN void (__cdecl *__MINGW_IMP_SYMBOL(_invoke_watson))(const wchar_t *, const wchar_t *, const wchar_t *, unsigned int, uintptr_t) = _invoke_watson;