ReactOS  0.4.14-dev-342-gdc047f9
pseh3.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS system libraries
3  * LICENSE: GNU GPL - See COPYING in the top level directory
4  * PURPOSE: Support library for PSEH3
5  * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org)
6  */
7 
8 /*
9  * - Naming: To avoid naming conflicts, all internal identifiers are prefixed
10  * with _SEH3$_.
11  * - Frame graph: PSEH3 uses the same registration frame for every trylevel.
12  * Only the top trylevel is registered in FS:0, the inner trylevels are linked
13  * to the first trylevel frame. Only the first trylevel frame has the Handler
14  * member set, it's 0 for all others as an identification. The EndOfChain
15  * member of the FS:0 registered frame points to the last internal frame,
16  * which is the frame itself, when only 1 trylevel is present.
17  *
18  * The registration graph looks like this:
19  *
20  * newer handlers
21  * ---------------->
22  *
23  * fs:0 /----------------\
24  * |-----------|<-\ |-----------|<-\ / |----------|<-\ \->|----------|
25  * | <Next> | \-| <Next> | \--/--| <Next> | \---| <Next> |
26  * | <Handler> | | <Handler> | / | <NULL> | | <NULL> |
27  * |-----------| |-----------| / |----------| |----------|
28  * |EndOfChain |---/
29  * | ... |
30  * |-----------|
31  */
32 
33 #include <stdarg.h>
34 #include <windef.h>
35 #include <winnt.h>
36 
37 /* We need the full structure with all non-volatile */
38 #define _SEH3$_FRAME_ALL_NONVOLATILES 1
39 #include "pseh3.h"
40 #include "pseh3_asmdef.h"
41 
42 /* Make sure the asm definitions match the structures */
52 #ifdef _SEH3$_FRAME_ALL_NONVOLATILES
56 #endif
57 #ifdef __clang__
59 #endif
62 
63 void
64 __attribute__((regparm(1)))
65 _SEH3$_Unregister(
66  volatile SEH3$_REGISTRATION_FRAME *Frame)
67 {
68  if (Frame->Handler)
69  _SEH3$_UnregisterFrame(Frame);
70  else
71  _SEH3$_UnregisterTryLevel(Frame);
72 }
73 
74 static inline
75 LONG
77  volatile SEH3$_REGISTRATION_FRAME *RegistrationFrame,
78  PVOID Filter)
79 {
80  LONG FilterResult;
81 
82  asm volatile (
83  /* First call with param = 0 to get the frame layout */
84  "xorl %%ecx, %%ecx\n\t"
85  "xorl %%eax, %%eax\n\t"
86  "call *%[Filter]\n\t"
87 
88  /* The result is the frame base address that we passed in (0) plus the
89  offset to the registration record. */
90  "negl %%eax\n\t"
91  "addl %[RegistrationFrame], %%eax\n\t"
92 
93  /* Second call to get the filter result */
94  "mov $1, %%ecx\n\t"
95  "call *%[Filter]"
96  : "=a" (FilterResult)
97  : [RegistrationFrame] "m" (RegistrationFrame), [Filter] "m" (Filter)
98  : "ecx", "edx");
99 
100  return FilterResult;
101 }
102 
103 long
104 __attribute__((regparm(1)))
105 _SEH3$_InvokeEmbeddedFilter(
106  volatile SEH3$_REGISTRATION_FRAME *RegistrationFrame);
107 
108 long
109 __attribute__((regparm(1)))
110 _SEH3$_InvokeEmbeddedFilterFromRegistration(
111  volatile SEH3$_REGISTRATION_FRAME *RegistrationFrame);
112 
113 static inline
114 LONG
115 _SEH3$_InvokeFilter(
116  volatile SEH3$_REGISTRATION_FRAME *RegistrationFrame,
117  PVOID Filter)
118 {
119  LONG FilterResult;
120 
121  if (RegistrationFrame->ScopeTable->HandlerType == _SEH3$_NESTED_HANDLER)
122  {
123  return _SEH3$_InvokeNestedFunctionFilter(RegistrationFrame, Filter);
124  }
125  else if (RegistrationFrame->ScopeTable->HandlerType == _SEH3$_CPP_HANDLER)
126  {
127  /* Call the embedded filter function */
128  return _SEH3$_InvokeEmbeddedFilter(RegistrationFrame);
129  }
130  else if (RegistrationFrame->ScopeTable->HandlerType == _SEH3$_CLANG_HANDLER)
131  {
132  return _SEH3$_InvokeEmbeddedFilterFromRegistration(RegistrationFrame);
133  }
134  else
135  {
136  /* Should not happen! Skip this handler */
137  FilterResult = EXCEPTION_CONTINUE_SEARCH;
138  }
139 
140  return FilterResult;
141 }
142 
143 void
144 __attribute__((regparm(1)))
145 _SEH3$_AutoCleanup(
146  volatile SEH3$_REGISTRATION_FRAME *Frame)
147 {
148  if (Frame->Handler)
149  _SEH3$_UnregisterFrame(Frame);
150  else
151  _SEH3$_UnregisterTryLevel(Frame);
152 
153  /* Check for __finally frames */
154  if (Frame->ScopeTable->Target == NULL)
155  {
156  _SEH3$_InvokeFilter(Frame, Frame->ScopeTable->Filter);
157  }
158 
159 }
160 
161 static inline
162 LONG
165 {
166  PVOID Filter = Record->ScopeTable->Filter;
167  LONG Result;
168 
169  /* Check for __finally frames */
170  if (Record->ScopeTable->Target == NULL)
171  {
173  }
174 
175  /* Check if we have a constant filter */
176  if (((ULONG)Filter & 0xFFFFFF00) == 0)
177  {
178  /* Lowest 8 bit are sign extended to give the result */
179  Result = (LONG)(CHAR)(ULONG)Filter;
180  }
181  else
182  {
183  /* Call the filter function */
184  Result = _SEH3$_InvokeFilter(Record, Filter);
185  }
186 
187  /* Normalize the result */
188  if (Result < 0) return EXCEPTION_CONTINUE_EXECUTION;
189  else if (Result > 0) return EXCEPTION_EXECUTE_HANDLER;
190  else return EXCEPTION_CONTINUE_SEARCH;
191 }
192 
193 static inline
194 VOID
197 {
198  _SEH3$_InvokeFilter(Record, Record->ScopeTable->Filter);
199 }
200 
201 __attribute__((noreturn))
202 static inline
203 void
204 _SEH3$_JumpToTarget(
205  PSEH3$_REGISTRATION_FRAME RegistrationFrame)
206 {
207  if (RegistrationFrame->ScopeTable->HandlerType == _SEH3$_CLANG_HANDLER)
208  {
209  asm volatile (
210  /* Load the registers */
211  "movl 24(%%ecx), %%esp\n\t"
212  "movl 28(%%ecx), %%ebp\n\t"
213 
214  "movl 36(%%ecx), %%ebx\n\t"
215  "movl 40(%%ecx), %%esi\n\t"
216  "movl 44(%%ecx), %%edi\n\t"
217 
218  /* Stack pointer is 4 off from the call to __SEH3$_RegisterFrame */
219  "addl $4, %%esp\n\t"
220 
221  /* Jump into the exception handler */
222  "jmp *%[Target]"
223  : :
224  "c" (RegistrationFrame),
225  "a" (RegistrationFrame->ScopeTable),
226  [Target] "m" (RegistrationFrame->ScopeTable->Target)
227  );
228  }
229  else
230  {
231  asm volatile (
232  /* Load the registers */
233  "movl 24(%%ecx), %%esp\n\t"
234  "movl 28(%%ecx), %%ebp\n\t"
235 
236  /* Stack pointer is 4 off from the call to __SEH3$_RegisterFrame */
237  "addl $4, %%esp\n\t"
238 
239  /* Jump into the exception handler */
240  "jmp *%[Target]"
241  : :
242  "c" (RegistrationFrame),
243  "a" (RegistrationFrame->ScopeTable),
244  [Target] "m" (RegistrationFrame->ScopeTable->Target)
245  );
246  }
247 
248  __builtin_unreachable();
249 }
250 
251 void
254  PSEH3$_REGISTRATION_FRAME RegistrationFrame);
255 
256 
258 __cdecl
259 #ifndef __clang__
260 __attribute__ ((__target__ ("cld")))
261 #endif
262 _SEH3$_except_handler(
263  struct _EXCEPTION_RECORD * ExceptionRecord,
265  struct _CONTEXT * ContextRecord,
266  void * DispatcherContext)
267 {
268  PSEH3$_REGISTRATION_FRAME CurrentFrame, TargetFrame;
269  SEH3$_EXCEPTION_POINTERS ExceptionPointers;
270  LONG FilterResult;
271 
272  /* Clear the direction flag. */
273  asm volatile ("cld" : : : "memory");
274 
275  /* Save the exception pointers on the stack */
276  ExceptionPointers.ExceptionRecord = ExceptionRecord;
277  ExceptionPointers.ContextRecord = ContextRecord;
278 
279  /* Check if this is an unwind */
280  if (ExceptionRecord->ExceptionFlags & EXCEPTION_UNWINDING)
281  {
282  /* Unwind all local frames */
283  TargetFrame = EstablisherFrame->Next;
284  }
285  else
286  {
287  /* Loop all frames for this registration */
288  CurrentFrame = EstablisherFrame->EndOfChain;
289  for (;;)
290  {
291  /* Check if we have an exception handler */
292  if (CurrentFrame->ScopeTable->Target != NULL)
293  {
294  /* Set exception pointers and code for this frame */
295  CurrentFrame->ExceptionPointers = &ExceptionPointers;
296  CurrentFrame->ExceptionCode = ExceptionRecord->ExceptionCode;
297 
298  /* Get the filter result */
299  FilterResult = _SEH3$_GetFilterResult(CurrentFrame);
300 
301  /* Check, if continuuing is requested */
302  if (FilterResult == EXCEPTION_CONTINUE_EXECUTION)
303  {
305  }
306 
307  /* Check if the except handler shall be executed */
308  if (FilterResult == EXCEPTION_EXECUTE_HANDLER) break;
309  }
310 
311  /* Bail out if this is the last handler */
312  if (CurrentFrame == EstablisherFrame)
314 
315  /* Go to the next frame */
316  CurrentFrame = CurrentFrame->Next;
317  }
318 
319  /* Call RtlUnwind to unwind the frames below this one */
321 
322  /* Do a local unwind up to this frame */
323  TargetFrame = CurrentFrame;
324  }
325 
326  /* Loop frames up to the target frame */
327  for (CurrentFrame = EstablisherFrame->EndOfChain;
328  CurrentFrame != TargetFrame;
329  CurrentFrame = CurrentFrame->Next)
330  {
331  /* Manually unregister the frame */
332  _SEH3$_Unregister(CurrentFrame);
333 
334  /* Check if this is an unwind frame */
335  if (CurrentFrame->ScopeTable->Target == NULL)
336  {
337  /* Set exception pointers and code for this frame */
338  CurrentFrame->ExceptionPointers = &ExceptionPointers;
339  CurrentFrame->ExceptionCode = ExceptionRecord->ExceptionCode;
340 
341  /* Call the finally function */
342  _SEH3$_CallFinally(CurrentFrame);
343  }
344  }
345 
346  /* Check if this was an unwind */
347  if (ExceptionRecord->ExceptionFlags & EXCEPTION_UNWINDING)
348  {
350  }
351 
352  /* Unregister the frame. It will be unregistered again at the end of the
353  __except block, due to auto cleanup, but that doesn't hurt.
354  All we do is set either fs:[0] or EstablisherFrame->EndOfChain to
355  CurrentFrame->Next, which will not change it's value. */
356  _SEH3$_Unregister(CurrentFrame);
357 
358  /* Jump to the __except block (does not return) */
359  _SEH3$_JumpToTarget(CurrentFrame);
360 }
361 
_Inout_ PIRP _In_ NTSTATUS ExceptionCode
Definition: cdprocs.h:1782
#define SEH3_REGISTRATION_FRAME_Ebp
Definition: pseh3_asmdef.h:10
int const SEH3 $_SCOPE_TABLE * ScopeTable
Definition: pseh3.h:133
_IRQL_requires_same_ _In_ PVOID EstablisherFrame
Definition: ntbasedef.h:660
#define __cdecl
Definition: accygwin.h:79
#define SEH3_REGISTRATION_FRAME_Edi
Definition: pseh3_asmdef.h:14
#define __fastcall
Definition: sync.c:41
char CHAR
Definition: xmlstorage.h:175
#define SEH3_SCOPE_TABLE_Filter
Definition: pseh3_asmdef.h:18
#define SEH3_REGISTRATION_FRAME_AllocaFrame
Definition: pseh3_asmdef.h:11
#define EXCEPTION_UNWINDING
Definition: rtltypes.h:151
#define SEH3_REGISTRATION_FRAME_Esp
Definition: pseh3_asmdef.h:9
static LONG _SEH3 $_GetFilterResult(PSEH3 $_REGISTRATION_FRAME Record)
Definition: pseh3.c:163
DWORD ExceptionCode
Definition: compat.h:196
void __fastcall _SEH3 $_CallRtlUnwind(PSEH3 $_REGISTRATION_FRAME RegistrationFrame)
_In_ struct _KBUGCHECK_REASON_CALLBACK_RECORD * Record
Definition: ketypes.h:256
#define EXCEPTION_CONTINUE_SEARCH
Definition: excpt.h:86
#define SEH3_REGISTRATION_FRAME_Handler
Definition: pseh3_asmdef.h:4
_IRQL_requires_same_ _In_ PVOID _Inout_ struct _CONTEXT _In_ PVOID DispatcherContext
Definition: ntbasedef.h:661
long LONG
Definition: pedump.c:60
_Must_inspect_result_ _In_opt_ PFLT_FILTER Filter
Definition: fltkernel.h:1802
#define _SEH3
Definition: pseh3.c:38
#define SEH3_REGISTRATION_FRAME_ExceptionPointers
Definition: pseh3_asmdef.h:7
#define SEH3_REGISTRATION_FRAME_ScopeTable
Definition: pseh3_asmdef.h:6
#define SEH3_REGISTRATION_FRAME_ExceptionCode
Definition: pseh3_asmdef.h:8
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
#define SEH3_REGISTRATION_FRAME_Next
Definition: pseh3_asmdef.h:3
smooth NULL
Definition: ftsmooth.c:416
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:426
#define inline
Definition: module.h:38
#define volatile
Definition: prototyp.h:117
C_ASSERT(SEH3_REGISTRATION_FRAME_Next==FIELD_OFFSET(SEH3 $_REGISTRATION_FRAME, Next))
void __attribute__((regparm(1)))
Definition: pseh3.c:64
#define SEH3_REGISTRATION_FRAME_EndOfChain
Definition: pseh3_asmdef.h:5
_Must_inspect_result_ typedef _In_ ULONG _In_ BOOLEAN Target
Definition: iotypes.h:1068
#define SEH3_REGISTRATION_FRAME_ReturnAddress
Definition: pseh3_asmdef.h:15
static VOID _SEH3 $_CallFinally(PSEH3 $_REGISTRATION_FRAME Record)
Definition: pseh3.c:195
_IRQL_requires_same_ _In_ PVOID _Inout_ struct _CONTEXT * ContextRecord
Definition: ntbasedef.h:661
int const SEH3 $_SCOPE_TABLE void * AllocaFrame
Definition: pseh3.h:133
#define SEH3_REGISTRATION_FRAME_Esi
Definition: pseh3_asmdef.h:13
static LONG _SEH3 $_InvokeNestedFunctionFilter(volatile SEH3 $_REGISTRATION_FRAME *RegistrationFrame, PVOID Filter)
Definition: pseh3.c:76
ACPI_PHYSICAL_ADDRESS ACPI_SIZE BOOLEAN Warn BOOLEAN Physical UINT32 ACPI_TABLE_HEADER *OutTableHeader ACPI_TABLE_HEADER **OutTable ACPI_HANDLE UINT32 ACPI_WALK_CALLBACK ACPI_WALK_CALLBACK void void **ReturnValue UINT32 ACPI_BUFFER *RetPathPtr ACPI_OBJECT_HANDLER Handler
Definition: acpixf.h:668
#define SEH3_SCOPE_TABLE_Target
Definition: pseh3_asmdef.h:17
struct _EXCEPTION_RECORD * ExceptionRecord
Definition: pseh3.h:54
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:254
unsigned int ULONG
Definition: retypes.h:1
enum _EXCEPTION_DISPOSITION EXCEPTION_DISPOSITION
DWORD ExceptionFlags
Definition: compat.h:197
#define EXCEPTION_CONTINUE_EXECUTION
Definition: excpt.h:87
#define SEH3_REGISTRATION_FRAME_Ebx
Definition: pseh3_asmdef.h:12