https://git.reactos.org/?p=reactos.git;a=commitdiff;h=0520c75aaf3a9334d209e6b5ec04f15cb9b773c4

commit 0520c75aaf3a9334d209e6b5ec04f15cb9b773c4
Author:     Timo Kreuzer <[email protected]>
AuthorDate: Thu Mar 1 14:22:18 2018 +0100
Commit:     Timo Kreuzer <[email protected]>
CommitDate: Sat Jun 5 13:52:42 2021 +0200

    [CRT] Implement __C_specific_handler
---
 sdk/lib/crt/except/amd64/ehandler.c | 132 ++++++++++++++++++++++++++++++++++--
 1 file changed, 125 insertions(+), 7 deletions(-)

diff --git a/sdk/lib/crt/except/amd64/ehandler.c 
b/sdk/lib/crt/except/amd64/ehandler.c
index 6e28e78e604..b32b821d6c9 100644
--- a/sdk/lib/crt/except/amd64/ehandler.c
+++ b/sdk/lib/crt/except/amd64/ehandler.c
@@ -1,19 +1,137 @@
+/*
+ * PROJECT:     ReactOS CRT library
+ * LICENSE:     MIT (https://spdx.org/licenses/MIT)
+ * PURPOSE:     C specific exception/unwind handler for AMD64
+ * COPYRIGHT:   Copyright 2018-2021 Timo Kreuzer <[email protected]>
+*/
 
 #include <precomp.h>
+#include <winnt.h>
 
 
 _CRTIMP
 EXCEPTION_DISPOSITION
 __cdecl
 __C_specific_handler(
-    struct _EXCEPTION_RECORD *_ExceptionRecord,
-    void *_EstablisherFrame,
-    struct _CONTEXT *_ContextRecord,
-    struct _DISPATCHER_CONTEXT *_DispatcherContext)
+    struct _EXCEPTION_RECORD *ExceptionRecord,
+    void *EstablisherFrame,
+    struct _CONTEXT *ContextRecord,
+    struct _DISPATCHER_CONTEXT *DispatcherContext)
 {
-    UNIMPLEMENTED;
-    __debugbreak();
-    return 0;
+    PSCOPE_TABLE ScopeTable;
+    ULONG i, BeginAddress, EndAddress, Handler;
+    ULONG64 ImageBase, JumpTarget, IpOffset, TargetIpOffset;
+    EXCEPTION_POINTERS ExceptionPointers;
+    PTERMINATION_HANDLER TerminationHandler;
+    PEXCEPTION_FILTER ExceptionFilter;
+    LONG FilterResult;
+
+    /* Set up the EXCEPTION_POINTERS */
+    ExceptionPointers.ExceptionRecord = ExceptionRecord;
+    ExceptionPointers.ContextRecord = ContextRecord;
+
+    /* Get the image base */
+    ImageBase = (ULONG64)DispatcherContext->ImageBase;
+
+    /* Get the image base relative instruction pointers */
+    IpOffset = DispatcherContext->ControlPc - ImageBase;
+    TargetIpOffset = DispatcherContext->TargetIp - ImageBase;
+
+    /* Get the scope table and current index */
+    ScopeTable = (PSCOPE_TABLE)DispatcherContext->HandlerData;
+
+    /* Loop while we have scope table entries */
+    while (DispatcherContext->ScopeIndex < ScopeTable->Count)
+    {
+        /* Use i as index and update the dispatcher context */
+        i = DispatcherContext->ScopeIndex++;
+
+        /* Get the start and end of the scrope */
+        BeginAddress = ScopeTable->ScopeRecord[i].BeginAddress;
+        EndAddress = ScopeTable->ScopeRecord[i].EndAddress;
+
+        /* Skip this scope if we are not within the bounds */
+        if ((IpOffset < BeginAddress) || (IpOffset >= EndAddress))
+        {
+            continue;
+        }
+
+        /* Check if this is an unwind */
+        if (ExceptionRecord->ExceptionFlags & EXCEPTION_UNWIND)
+        {
+            /* Check if this is a target unwind */
+            if (ExceptionRecord->ExceptionFlags & EXCEPTION_TARGET_UNWIND)
+            {
+                /* Check if the target is within the scope itself */
+                if ((TargetIpOffset >= BeginAddress) &&
+                    (TargetIpOffset <  EndAddress))
+                {
+                    return ExceptionContinueSearch;
+                }
+            }
+
+            /* Check if this is a termination handler / finally function */
+            if (ScopeTable->ScopeRecord[i].JumpTarget == 0)
+            {
+                /* Call the handler */
+                Handler = ScopeTable->ScopeRecord[i].HandlerAddress;
+                TerminationHandler = (PTERMINATION_HANDLER)(ImageBase + 
Handler);
+                TerminationHandler(TRUE, EstablisherFrame);
+            }
+            else if (ScopeTable->ScopeRecord[i].JumpTarget == TargetIpOffset)
+            {
+                return ExceptionContinueSearch;
+            }
+        }
+        else
+        {
+            /* We are only unterested in exception handlers */
+            if (ScopeTable->ScopeRecord[i].JumpTarget == 0)
+            {
+                continue;
+            }
+
+            /* This is an exception filter, get the handler address */
+            Handler = ScopeTable->ScopeRecord[i].HandlerAddress;
+
+            /* Check for hardcoded EXCEPTION_EXECUTE_HANDLER */
+            if (Handler == EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* This is our result */
+                FilterResult = EXCEPTION_EXECUTE_HANDLER;
+            }
+            else
+            {
+                /* Otherwise we need to call the handler */
+                ExceptionFilter = (PEXCEPTION_FILTER)(ImageBase + Handler);
+                FilterResult = ExceptionFilter(&ExceptionPointers, 
EstablisherFrame);
+            }
+
+            if (FilterResult == EXCEPTION_CONTINUE_EXECUTION)
+            {
+                return ExceptionContinueExecution;
+            }
+
+            if (FilterResult == EXCEPTION_EXECUTE_HANDLER)
+            {
+                JumpTarget = (ImageBase + 
ScopeTable->ScopeRecord[i].JumpTarget);
+
+                /* Unwind to the target address (This does not return) */
+                RtlUnwindEx(EstablisherFrame,
+                            (PVOID)JumpTarget,
+                            ExceptionRecord,
+                            UlongToPtr(ExceptionRecord->ExceptionCode),
+                            DispatcherContext->ContextRecord,
+                            DispatcherContext->HistoryTable);
+
+                /* Should not get here */
+                __debugbreak();
+            }
+        }
+    }
+
+    /* Reached the end of the scope table */
+    return ExceptionContinueSearch;
 }
 
 void __cdecl _local_unwind(void* frame, void* target)

Reply via email to