From 0520c75aaf3a9334d209e6b5ec04f15cb9b773c4 Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Thu, 1 Mar 2018 14:22:18 +0100 Subject: [PATCH] [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 +*/ #include +#include _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)