xref: /reactos/sdk/lib/crt/except/amd64/ehandler.c (revision 53221834)
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