1 /* 2 * PROJECT: ReactOS CRT library 3 * LICENSE: MIT (https://spdx.org/licenses/MIT) 4 * PURPOSE: C specific exception/unwind handler for AMD64 5 * COPYRIGHT: Copyright 2018-2021 Timo Kreuzer <timo.kreuzer@reactos.org> 6 */ 7 8 #include <precomp.h> 9 #include <winnt.h> 10 11 12 _CRTIMP 13 EXCEPTION_DISPOSITION 14 __cdecl 15 __C_specific_handler( 16 struct _EXCEPTION_RECORD *ExceptionRecord, 17 void *EstablisherFrame, 18 struct _CONTEXT *ContextRecord, 19 struct _DISPATCHER_CONTEXT *DispatcherContext) 20 { 21 PSCOPE_TABLE ScopeTable; 22 ULONG i, BeginAddress, EndAddress, Handler; 23 ULONG64 ImageBase, JumpTarget, IpOffset, TargetIpOffset; 24 EXCEPTION_POINTERS ExceptionPointers; 25 PTERMINATION_HANDLER TerminationHandler; 26 PEXCEPTION_FILTER ExceptionFilter; 27 LONG FilterResult; 28 29 /* Set up the EXCEPTION_POINTERS */ 30 ExceptionPointers.ExceptionRecord = ExceptionRecord; 31 ExceptionPointers.ContextRecord = ContextRecord; 32 33 /* Get the image base */ 34 ImageBase = (ULONG64)DispatcherContext->ImageBase; 35 36 /* Get the image base relative instruction pointers */ 37 IpOffset = DispatcherContext->ControlPc - ImageBase; 38 TargetIpOffset = DispatcherContext->TargetIp - ImageBase; 39 40 /* Get the scope table and current index */ 41 ScopeTable = (PSCOPE_TABLE)DispatcherContext->HandlerData; 42 43 /* Loop while we have scope table entries */ 44 while (DispatcherContext->ScopeIndex < ScopeTable->Count) 45 { 46 /* Use i as index and update the dispatcher context */ 47 i = DispatcherContext->ScopeIndex++; 48 49 /* Get the start and end of the scrope */ 50 BeginAddress = ScopeTable->ScopeRecord[i].BeginAddress; 51 EndAddress = ScopeTable->ScopeRecord[i].EndAddress; 52 53 /* Skip this scope if we are not within the bounds */ 54 if ((IpOffset < BeginAddress) || (IpOffset >= EndAddress)) 55 { 56 continue; 57 } 58 59 /* Check if this is an unwind */ 60 if (ExceptionRecord->ExceptionFlags & EXCEPTION_UNWIND) 61 { 62 /* Check if this is a target unwind */ 63 if (ExceptionRecord->ExceptionFlags & EXCEPTION_TARGET_UNWIND) 64 { 65 /* Check if the target is within the scope itself */ 66 if ((TargetIpOffset >= BeginAddress) && 67 (TargetIpOffset < EndAddress)) 68 { 69 return ExceptionContinueSearch; 70 } 71 } 72 73 /* Check if this is a termination handler / finally function */ 74 if (ScopeTable->ScopeRecord[i].JumpTarget == 0) 75 { 76 /* Call the handler */ 77 Handler = ScopeTable->ScopeRecord[i].HandlerAddress; 78 TerminationHandler = (PTERMINATION_HANDLER)(ImageBase + Handler); 79 TerminationHandler(TRUE, EstablisherFrame); 80 } 81 else if (ScopeTable->ScopeRecord[i].JumpTarget == TargetIpOffset) 82 { 83 return ExceptionContinueSearch; 84 } 85 } 86 else 87 { 88 /* We are only unterested in exception handlers */ 89 if (ScopeTable->ScopeRecord[i].JumpTarget == 0) 90 { 91 continue; 92 } 93 94 /* This is an exception filter, get the handler address */ 95 Handler = ScopeTable->ScopeRecord[i].HandlerAddress; 96 97 /* Check for hardcoded EXCEPTION_EXECUTE_HANDLER */ 98 if (Handler == EXCEPTION_EXECUTE_HANDLER) 99 { 100 /* This is our result */ 101 FilterResult = EXCEPTION_EXECUTE_HANDLER; 102 } 103 else 104 { 105 /* Otherwise we need to call the handler */ 106 ExceptionFilter = (PEXCEPTION_FILTER)(ImageBase + Handler); 107 FilterResult = ExceptionFilter(&ExceptionPointers, EstablisherFrame); 108 } 109 110 if (FilterResult == EXCEPTION_CONTINUE_EXECUTION) 111 { 112 return ExceptionContinueExecution; 113 } 114 115 if (FilterResult == EXCEPTION_EXECUTE_HANDLER) 116 { 117 JumpTarget = (ImageBase + ScopeTable->ScopeRecord[i].JumpTarget); 118 119 /* Unwind to the target address (This does not return) */ 120 RtlUnwindEx(EstablisherFrame, 121 (PVOID)JumpTarget, 122 ExceptionRecord, 123 UlongToPtr(ExceptionRecord->ExceptionCode), 124 DispatcherContext->ContextRecord, 125 DispatcherContext->HistoryTable); 126 127 /* Should not get here */ 128 __debugbreak(); 129 } 130 } 131 } 132 133 /* Reached the end of the scope table */ 134 return ExceptionContinueSearch; 135 } 136 137 void __cdecl _local_unwind(void* frame, void* target) 138 { 139 RtlUnwind(frame, target, NULL, 0); 140 } 141