[NativeAOT] correctly initalize CONTEXT before failing fast (#81010)
authorAustin Wise <AustinWise@gmail.com>
Mon, 6 Feb 2023 02:51:48 +0000 (18:51 -0800)
committerGitHub <noreply@github.com>
Mon, 6 Feb 2023 02:51:48 +0000 (18:51 -0800)
* [NativeAOT] correctly initalize CONTEXT before failing fast

* Switch from using GetThreadContext to RtlCaptureContext.

* Add a better explination of why the function is unimplmented on Unix.

* Update src/coreclr/nativeaot/Runtime/PalRedhawk.h

Co-authored-by: Vladimir Sadov <vsadov@microsoft.com>
* Respond to feedback: unconditionally set CONTEXT_CONTROL

* Respond to feedback: consolidate setting of ContextFlags.

* On second thought, don't add a second layer of ifdef nesting.

---------

Co-authored-by: Vladimir Sadov <vsadov@microsoft.com>
src/coreclr/nativeaot/Runtime/EHHelpers.cpp
src/coreclr/nativeaot/Runtime/PalRedhawk.h
src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp
src/coreclr/nativeaot/Runtime/windows/PalRedhawkMinWin.cpp

index 4228708c4103b25dfbd8aa37cf8bda4643c7762b..b25beb3bb0c584d75c297efaa3f0b0b041f269df 100644 (file)
@@ -90,9 +90,19 @@ COOP_PINVOKE_HELPER(int32_t, RhGetModuleFileName, (HANDLE moduleHandle, _Out_ co
 
 COOP_PINVOKE_HELPER(void, RhpCopyContextFromExInfo, (void * pOSContext, int32_t cbOSContext, PAL_LIMITED_CONTEXT * pPalContext))
 {
-    UNREFERENCED_PARAMETER(cbOSContext);
     ASSERT((size_t)cbOSContext >= sizeof(CONTEXT));
     CONTEXT* pContext = (CONTEXT *)pOSContext;
+
+#ifndef HOST_WASM
+
+    memset(pOSContext, 0, cbOSContext);
+    pContext->ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
+
+    // Fill in CONTEXT_CONTROL registers that were not captured in PAL_LIMITED_CONTEXT.
+    PopulateControlSegmentRegisters(pContext);
+
+#endif // !HOST_WASM
+
 #if defined(UNIX_AMD64_ABI)
     pContext->Rip = pPalContext->IP;
     pContext->Rsp = pPalContext->Rsp;
index 6b14fcb2b20ccc23fa0abee1439a8e9e148795cb..f758883745f3528fc1571dc4948aaf7a6eefa8b9 100644 (file)
@@ -112,6 +112,11 @@ struct FILETIME
 
 #ifdef HOST_AMD64
 
+#define CONTEXT_AMD64   0x00100000L
+
+#define CONTEXT_CONTROL         (CONTEXT_AMD64 | 0x00000001L)
+#define CONTEXT_INTEGER         (CONTEXT_AMD64 | 0x00000002L)
+
 typedef struct DECLSPEC_ALIGN(16) _XSAVE_FORMAT {
     uint16_t  ControlWord;
     uint16_t  StatusWord;
@@ -232,6 +237,11 @@ typedef struct DECLSPEC_ALIGN(16) _CONTEXT {
 } CONTEXT, *PCONTEXT;
 #elif defined(HOST_ARM)
 
+#define CONTEXT_ARM   0x00200000L
+
+#define CONTEXT_CONTROL (CONTEXT_ARM | 0x1L)
+#define CONTEXT_INTEGER (CONTEXT_ARM | 0x2L)
+
 #define ARM_MAX_BREAKPOINTS     8
 #define ARM_MAX_WATCHPOINTS     1
 
@@ -275,6 +285,12 @@ typedef struct DECLSPEC_ALIGN(8) _CONTEXT {
 } CONTEXT, *PCONTEXT;
 
 #elif defined(HOST_X86)
+
+#define CONTEXT_i386    0x00010000L
+
+#define CONTEXT_CONTROL         (CONTEXT_i386 | 0x00000001L) // SS:SP, CS:IP, FLAGS, BP
+#define CONTEXT_INTEGER         (CONTEXT_i386 | 0x00000002L) // AX, BX, CX, DX, SI, DI
+
 #define SIZE_OF_80387_REGISTERS      80
 #define MAXIMUM_SUPPORTED_EXTENSION  512
 
@@ -329,6 +345,11 @@ typedef struct _CONTEXT {
 
 #elif defined(HOST_ARM64)
 
+#define CONTEXT_ARM64   0x00400000L
+
+#define CONTEXT_CONTROL (CONTEXT_ARM64 | 0x1L)
+#define CONTEXT_INTEGER (CONTEXT_ARM64 | 0x2L)
+
 // Specify the number of breakpoints and watchpoints that the OS
 // will track. Architecturally, ARM64 supports up to 16. In practice,
 // however, almost no one implements more than 4 of each.
@@ -614,6 +635,11 @@ REDHAWK_PALIMPORT bool REDHAWK_PALAPI PalGetCompleteThreadContext(HANDLE hThread
 REDHAWK_PALIMPORT bool REDHAWK_PALAPI PalSetThreadContext(HANDLE hThread, _Out_ CONTEXT * pCtx);
 REDHAWK_PALIMPORT void REDHAWK_PALAPI PalRestoreContext(CONTEXT * pCtx);
 
+// For platforms that have segment registers in the CONTEXT_CONTROL set that
+// are not saved in PAL_LIMITED_CONTEXT, this captures them from the current
+// thread and saves them in `pContext`.
+REDHAWK_PALIMPORT void REDHAWK_PALAPI PopulateControlSegmentRegisters(CONTEXT* pContext);
+
 REDHAWK_PALIMPORT int32_t REDHAWK_PALAPI PalGetProcessCpuCount();
 
 // Retrieves the entire range of memory dedicated to the calling thread's stack.  This does
index 2893bc6289758e40debca7bae90176477986a332..4750908eb8d858bd6ef680e8ec70a2397586c850 100644 (file)
@@ -1068,6 +1068,14 @@ extern "C" int32_t _stricmp(const char *string1, const char *string2)
     return strcasecmp(string1, string2);
 }
 
+REDHAWK_PALIMPORT void REDHAWK_PALAPI PopulateControlSegmentRegisters(CONTEXT* pContext)
+{
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
+    // Currently the CONTEXT is only used on Windows for RaiseFailFastException.
+    // So we punt on filling in SegCs and SegSs for now.
+#endif
+}
+
 uint32_t g_RhNumberOfProcessors;
 
 REDHAWK_PALEXPORT int32_t PalGetProcessCpuCount()
index 8e8b85356b28d555451f5d34c85dd2f4ceb3563c..e6e304e7c3d2c7fae6f752d7db8405d55a596993 100644 (file)
@@ -446,6 +446,18 @@ REDHAWK_PALEXPORT void REDHAWK_PALAPI PalRestoreContext(CONTEXT * pCtx)
     RtlRestoreContext(pCtx, NULL);
 }
 
+REDHAWK_PALIMPORT void REDHAWK_PALAPI PopulateControlSegmentRegisters(CONTEXT* pContext)
+{
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
+    CONTEXT ctx;
+
+    RtlCaptureContext(&ctx);
+
+    pContext->SegCs = ctx.SegCs;
+    pContext->SegSs = ctx.SegSs;
+#endif //defined(TARGET_X86) || defined(TARGET_AMD64)
+}
+
 static PalHijackCallback g_pHijackCallback;
 
 #ifdef FEATURE_SPECIAL_USER_MODE_APC