On Sun, 31 Aug 2025, Pali Rohár wrote:

diff --git a/mingw-w64-crt/misc/_invoke_watson.c 
b/mingw-w64-crt/misc/_invoke_watson.c
new file mode 100644
index 000000000000..a7fa505024b2
--- /dev/null
+++ b/mingw-w64-crt/misc/_invoke_watson.c
@@ -0,0 +1,105 @@
+/**
+ * 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

Shouldn't we do something similar to this for arm/aarch64 too?

// Martin

_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to