ReactOS 0.4.16-dev-1506-g117cd33
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/* We need the full structure with all non-volatile */
34#define _SEH3$_FRAME_ALL_NONVOLATILES 1
35
36#include <stdarg.h>
37#include <windef.h>
38#include <winnt.h>
39
40#define ASSERT(exp) if (!(exp)) __int2c();
41
42#include "pseh3.h"
43#include "pseh3_asmdef.h"
44
45/* Make sure the asm definitions match the structures */
56#ifdef _SEH3$_FRAME_ALL_NONVOLATILES
60#endif
61#ifdef __clang__
63#endif
66
67enum
68{
72};
73
74void
75__attribute__((regparm(1)))
76_SEH3$_Unregister(
78{
79 volatile SEH3$_REGISTRATION_FRAME *CurrentFrame;
80
81 /* Check if the frame has a handler (then it's the registered frame) */
82 if (Frame->Handler != NULL)
83 {
84 /* There shouldn't be any more nested try-level frames */
85 ASSERT(Frame->EndOfChain == Frame);
86
87 /* During unwinding on Windows ExecuteHandler2 installs its own EH frame,
88 so there can be one or even multiple frames before our own one and we
89 need to search for the link that points to our head frame. */
90 CurrentFrame = (SEH3$_REGISTRATION_FRAME*)__readfsdword(0);
91 if (Frame == CurrentFrame)
92 {
93 /* The target frame is the first installed frame, remove it */
94 __writefsdword(0, (ULONG)Frame->Next);
95 return;
96 }
97
98 /* Loop to find the frame that links the target frame */
99 while (CurrentFrame->Next != Frame)
100 {
101 CurrentFrame = CurrentFrame->Next;
102 }
103
104 /* Remove the frame from the linked list */
105 CurrentFrame->Next = Frame->Next;
106 }
107 else
108 {
109 /* Search for the head frame */
110 CurrentFrame = Frame->Next;
111 while (CurrentFrame->Handler == NULL)
112 {
113 CurrentFrame = CurrentFrame->Next;
114 }
115
116 /* Make sure the head frame points to our frame */
117 ASSERT(CurrentFrame->EndOfChain == Frame);
118
119 /* Remove this frame from the internal linked list */
120 CurrentFrame->EndOfChain = Frame->Next;
121 }
122}
123
124static inline
125LONG
127 volatile SEH3$_REGISTRATION_FRAME *RegistrationFrame,
129{
130 LONG FilterResult;
131
132 asm volatile (
133 /* First call with param = 0 to get the frame layout */
134 "xorl %%ecx, %%ecx\n\t"
135 "xorl %%eax, %%eax\n\t"
136 "call *%[Filter]\n\t"
137
138 /* The result is the frame base address that we passed in (0) plus the
139 offset to the registration record. */
140 "negl %%eax\n\t"
141 "addl %[RegistrationFrame], %%eax\n\t"
142
143 /* Second call to get the filter result */
144 "mov $1, %%ecx\n\t"
145 "call *%[Filter]"
146 : "=a" (FilterResult)
147 : [RegistrationFrame] "m" (RegistrationFrame), [Filter] "m" (Filter)
148 : "ecx", "edx");
149
150 return FilterResult;
151}
152
153long
154__attribute__((regparm(1)))
155_SEH3$_InvokeEmbeddedFilter(
156 volatile SEH3$_REGISTRATION_FRAME *RegistrationFrame);
157
158long
159__attribute__((regparm(1)))
160_SEH3$_InvokeEmbeddedFilterFromRegistration(
161 volatile SEH3$_REGISTRATION_FRAME *RegistrationFrame);
162
163static inline
164LONG
165_SEH3$_InvokeFilter(
166 volatile SEH3$_REGISTRATION_FRAME *RegistrationFrame,
168 int HandlerType)
169{
170 LONG FilterResult;
171
173 {
174 return _SEH3$_InvokeNestedFunctionFilter(RegistrationFrame, Filter);
175 }
177 {
178 /* Call the embedded filter function */
179 return _SEH3$_InvokeEmbeddedFilter(RegistrationFrame);
180 }
182 {
183 return _SEH3$_InvokeEmbeddedFilterFromRegistration(RegistrationFrame);
184 }
185 else
186 {
187 /* Should not happen! Skip this handler */
188 FilterResult = EXCEPTION_CONTINUE_SEARCH;
189 }
190
191 return FilterResult;
192}
193
194void
195__attribute__((regparm(1)))
196_SEH3$_C_AutoCleanup(
198{
199 _SEH3$_Unregister(Frame);
200
201 /* Check for __finally frames */
202 if (Frame->ScopeTable->Target == NULL)
203 {
204#ifdef __clang__
205 _SEH3$_InvokeFilter(Frame, Frame->ScopeTable->Filter, _SEH3$_CLANG_HANDLER);
206#else
207 _SEH3$_InvokeFilter(Frame, Frame->ScopeTable->Filter, _SEH3$_NESTED_HANDLER);
208#endif
209 }
210}
211
212void
213__attribute__((regparm(1)))
214_SEH3$_CPP_AutoCleanup(
216{
217 if (Frame->Handler)
218 _SEH3$_UnregisterFrame(Frame);
219 else
220 _SEH3$_UnregisterTryLevel(Frame);
221
222 /* Check for __finally frames */
223 if (Frame->ScopeTable->Target == NULL)
224 {
225 _SEH3$_InvokeFilter(Frame, Frame->ScopeTable->Filter, _SEH3$_CPP_HANDLER);
226 }
227}
228
229
230static inline
231LONG
234 int HandlerType)
235{
236 PVOID Filter = Record->ScopeTable->Filter;
237 LONG Result;
238
239 /* Check if we have a constant filter */
240 if (((ULONG)Filter & 0xFFFFFF00) == 0)
241 {
242 /* Lowest 8 bit are sign extended to give the result */
244 }
245 else
246 {
247 /* Call the filter function */
248 Result = _SEH3$_InvokeFilter(Record, Filter, HandlerType);
249 }
250
251 /* Normalize the result */
252 if (Result < 0) return EXCEPTION_CONTINUE_EXECUTION;
253 else if (Result > 0) return EXCEPTION_EXECUTE_HANDLER;
254 else return EXCEPTION_CONTINUE_SEARCH;
255}
256
257static inline
258VOID
261 int HandlerType)
262{
263 _SEH3$_InvokeFilter(Record, Record->ScopeTable->Filter, HandlerType);
264}
265
266__attribute__((noreturn))
267static inline
268void
269_SEH3$_JumpToTarget(
270 PSEH3$_REGISTRATION_FRAME RegistrationFrame)
271{
272#ifdef __clang__
273 asm volatile (
274 /* Load the registers */
275 "movl 24(%%ecx), %%esp\n\t"
276 "movl 28(%%ecx), %%ebp\n\t"
277
278 "movl 36(%%ecx), %%ebx\n\t"
279 "movl 40(%%ecx), %%esi\n\t"
280 "movl 44(%%ecx), %%edi\n\t"
281
282 /* Stack pointer is 4 off from the call to __SEH3$_RegisterFrame */
283 "addl $4, %%esp\n\t"
284
285 /* Jump into the exception handler */
286 "jmp *%[Target]"
287 : :
288 "c" (RegistrationFrame),
289 "a" (RegistrationFrame->ScopeTable),
290 [Target] "m" (RegistrationFrame->ScopeTable->Target)
291 );
292#else
293 asm volatile (
294 /* Load the registers */
295 "movl 24(%%ecx), %%esp\n\t"
296 "movl 28(%%ecx), %%ebp\n\t"
297
298 /* Stack pointer is 4 off from the call to __SEH3$_RegisterFrame */
299 "addl $4, %%esp\n\t"
300
301 /* Jump into the exception handler */
302 "jmp *%[Target]"
303 : :
304 "c" (RegistrationFrame),
305 "a" (RegistrationFrame->ScopeTable),
306 [Target] "m" (RegistrationFrame->ScopeTable->Target)
307 );
308#endif
309
310 __builtin_unreachable();
311}
312
313void
316 PSEH3$_REGISTRATION_FRAME RegistrationFrame);
317
318
319int // EXCEPTION_DISPOSITION
321#ifndef __clang__
322__attribute__ ((__target__ ("cld")))
323#endif
324_SEH3$_common_except_handler(
325 struct _EXCEPTION_RECORD * ExceptionRecord,
327 struct _CONTEXT * ContextRecord,
328 void * DispatcherContext,
329 int HandlerType)
330{
331 PSEH3$_REGISTRATION_FRAME CurrentFrame, TargetFrame;
332 SEH3$_EXCEPTION_POINTERS ExceptionPointers;
333 LONG FilterResult;
334
335 /* Clear the direction flag. */
336 asm volatile ("cld" : : : "memory");
337
338 /* Save the exception pointers on the stack */
339 ExceptionPointers.ExceptionRecord = ExceptionRecord;
340 ExceptionPointers.ContextRecord = ContextRecord;
341
342 /* Check if this is an unwind */
343 if (IS_UNWINDING(ExceptionRecord->ExceptionFlags))
344 {
345 /* Unwind all local frames */
346 TargetFrame = EstablisherFrame->Next;
347 }
348 else
349 {
350 /* Loop all frames for this registration */
351 CurrentFrame = EstablisherFrame->EndOfChain;
352 for (;;)
353 {
354 /* Check if we have an exception handler */
355 if (CurrentFrame->ScopeTable->Target != NULL)
356 {
357 /* Set exception pointers and code for this frame */
358 CurrentFrame->ExceptionPointers = &ExceptionPointers;
359 CurrentFrame->ExceptionCode = ExceptionRecord->ExceptionCode;
360
361 /* Get the filter result */
362 FilterResult = _SEH3$_GetFilterResult(CurrentFrame, HandlerType);
363
364 /* Check, if continuuing is requested */
365 if (FilterResult == EXCEPTION_CONTINUE_EXECUTION)
366 {
368 }
369
370 /* Check if the except handler shall be executed */
371 if (FilterResult == EXCEPTION_EXECUTE_HANDLER) break;
372 }
373
374 /* Bail out if this is the last handler */
375 if (CurrentFrame == EstablisherFrame)
377
378 /* Go to the next frame */
379 CurrentFrame = CurrentFrame->Next;
380 }
381
382 /* Call RtlUnwind to unwind the frames below this one */
384
385 /* Do a local unwind up to this frame */
386 TargetFrame = CurrentFrame;
387 }
388
389 /* Loop frames up to the target frame */
390 for (CurrentFrame = EstablisherFrame->EndOfChain;
391 CurrentFrame != TargetFrame;
392 CurrentFrame = CurrentFrame->Next)
393 {
394 /* Manually unregister the frame */
395 _SEH3$_Unregister(CurrentFrame);
396
397 /* Check if this is an unwind frame */
398 if (CurrentFrame->ScopeTable->Target == NULL)
399 {
400 /* Set exception pointers and code for this frame */
401 CurrentFrame->ExceptionPointers = &ExceptionPointers;
402 CurrentFrame->ExceptionCode = ExceptionRecord->ExceptionCode;
403
404 /* Call the finally function */
405 _SEH3$_CallFinally(CurrentFrame, HandlerType);
406 }
407 }
408
409 /* Check if this was an unwind */
410 if (ExceptionRecord->ExceptionFlags & EXCEPTION_UNWINDING)
411 {
413 }
414
415 /* Unregister the frame. It will be unregistered again at the end of the
416 __except block, due to auto cleanup, but that doesn't hurt.
417 All we do is set either fs:[0] or EstablisherFrame->EndOfChain to
418 CurrentFrame->Next, which will not change it's value. */
419 _SEH3$_Unregister(CurrentFrame);
420
421 /* Jump to the __except block (does not return) */
422 _SEH3$_JumpToTarget(CurrentFrame);
423}
424
425int // EXCEPTION_DISPOSITION
428 struct _EXCEPTION_RECORD* ExceptionRecord,
430 struct _CONTEXT* ContextRecord,
431 void* DispatcherContext)
432{
433#ifdef __clang__
434 return _SEH3$_common_except_handler(ExceptionRecord, EstablisherFrame, ContextRecord, DispatcherContext, _SEH3$_CLANG_HANDLER);
435#else
436 return _SEH3$_common_except_handler(ExceptionRecord, EstablisherFrame, ContextRecord, DispatcherContext, _SEH3$_NESTED_HANDLER);
437#endif
438}
439
440int // EXCEPTION_DISPOSITION
443 struct _EXCEPTION_RECORD* ExceptionRecord,
445 struct _CONTEXT* ContextRecord,
446 void* DispatcherContext)
447{
448 return _SEH3$_common_except_handler(ExceptionRecord, EstablisherFrame, ContextRecord, DispatcherContext, _SEH3$_CPP_HANDLER);
449}
#define __cdecl
Definition: accygwin.h:79
ACPI_PHYSICAL_ADDRESS ACPI_SIZE BOOLEAN Warn UINT32 *TableIdx 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 void *Data ACPI_OBJECT_HANDLER void **Data ACPI_STRING ACPI_OBJECT_LIST ACPI_BUFFER *ReturnObjectBuffer ACPI_DEVICE_INFO **ReturnBuffer ACPI_HANDLE ACPI_HANDLE ACPI_HANDLE *OutHandle ACPI_HANDLE *OutHandle void *Context void *Context ACPI_EVENT_HANDLER Handler UINT32 UINT32 ACPI_GPE_HANDLER void *Context UINT32 HandlerType
Definition: acpixf.h:817
ACPI_PHYSICAL_ADDRESS ACPI_SIZE BOOLEAN Warn UINT32 *TableIdx 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:672
_Inout_ PIRP _In_ NTSTATUS ExceptionCode
Definition: cdprocs.h:1774
#define NULL
Definition: types.h:112
#define __attribute__(x)
Definition: wpp_private.h:207
@ ExceptionContinueSearch
Definition: compat.h:91
@ ExceptionContinueExecution
Definition: compat.h:90
_Must_inspect_result_ _In_opt_ PFLT_FILTER Filter
Definition: fltkernel.h:1801
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:90
#define EXCEPTION_CONTINUE_SEARCH
Definition: excpt.h:91
#define EXCEPTION_CONTINUE_EXECUTION
Definition: excpt.h:92
HRESULT Next([in] ULONG celt, [out, size_is(celt), length_is(*pceltFetched)] STATPROPSETSTG *rgelt, [out] ULONG *pceltFetched)
PPC_QUAL void __writefsdword(const unsigned long Offset, const unsigned long Data)
Definition: intrin_ppc.h:354
PPC_QUAL unsigned long __readfsdword(const unsigned long Offset)
Definition: intrin_ppc.h:382
#define C_ASSERT(e)
Definition: intsafe.h:73
#define __fastcall
Definition: sync.c:38
_IRQL_requires_same_ _In_ PVOID EstablisherFrame
Definition: ntbasedef.h:665
_IRQL_requires_same_ _In_ PVOID _Inout_ struct _CONTEXT * ContextRecord
Definition: ntbasedef.h:666
_IRQL_requires_same_ _In_ PVOID _Inout_ struct _CONTEXT _In_ PVOID DispatcherContext
Definition: ntbasedef.h:667
long LONG
Definition: pedump.c:60
#define volatile
Definition: prototyp.h:117
#define ASSERT(exp)
Definition: pseh3.c:40
int __cdecl _SEH3$_C_except_handler(struct _EXCEPTION_RECORD *ExceptionRecord, PSEH3$_REGISTRATION_FRAME EstablisherFrame, struct _CONTEXT *ContextRecord, void *DispatcherContext)
Definition: pseh3.c:427
int __cdecl _SEH3$_CPP_except_handler(struct _EXCEPTION_RECORD *ExceptionRecord, PSEH3$_REGISTRATION_FRAME EstablisherFrame, struct _CONTEXT *ContextRecord, void *DispatcherContext)
Definition: pseh3.c:442
void __fastcall _SEH3$_CallRtlUnwind(PSEH3$_REGISTRATION_FRAME RegistrationFrame)
static VOID _SEH3$_CallFinally(PSEH3$_REGISTRATION_FRAME Record, int HandlerType)
Definition: pseh3.c:259
static LONG _SEH3$_GetFilterResult(PSEH3$_REGISTRATION_FRAME Record, int HandlerType)
Definition: pseh3.c:232
@ _SEH3$_CLANG_HANDLER
Definition: pseh3.c:71
@ _SEH3$_CPP_HANDLER
Definition: pseh3.c:70
@ _SEH3$_NESTED_HANDLER
Definition: pseh3.c:69
static LONG _SEH3$_InvokeNestedFunctionFilter(volatile SEH3$_REGISTRATION_FRAME *RegistrationFrame, PVOID Filter)
Definition: pseh3.c:126
int const SEH3$_SCOPE_TABLE void * AllocaFrame
Definition: pseh3.h:132
int const SEH3$_SCOPE_TABLE * ScopeTable
Definition: pseh3.h:131
#define SEH3_REGISTRATION_FRAME_AllocaFrame
Definition: pseh3_asmdef.h:12
#define SEH3_REGISTRATION_FRAME_ExceptionPointers
Definition: pseh3_asmdef.h:8
#define SEH3_SCOPE_TABLE_Target
Definition: pseh3_asmdef.h:20
#define SEH3_REGISTRATION_FRAME_Handler
Definition: pseh3_asmdef.h:4
#define SEH3_REGISTRATION_FRAME_Esp
Definition: pseh3_asmdef.h:9
#define SEH3_REGISTRATION_FRAME_EndOfChain
Definition: pseh3_asmdef.h:7
#define SEH3_REGISTRATION_FRAME_Ebp
Definition: pseh3_asmdef.h:10
#define SEH3_SCOPE_TABLE_Filter
Definition: pseh3_asmdef.h:19
#define SEH3_REGISTRATION_FRAME_TryLevel
Definition: pseh3_asmdef.h:6
#define SEH3_REGISTRATION_FRAME_Edi
Definition: pseh3_asmdef.h:15
#define SEH3_REGISTRATION_FRAME_Esi
Definition: pseh3_asmdef.h:14
#define SEH3_REGISTRATION_FRAME_ReturnAddress
Definition: pseh3_asmdef.h:16
#define SEH3_REGISTRATION_FRAME_Next
Definition: pseh3_asmdef.h:3
#define SEH3_REGISTRATION_FRAME_ScopeTable
Definition: pseh3_asmdef.h:5
#define SEH3_REGISTRATION_FRAME_Ebx
Definition: pseh3_asmdef.h:13
#define SEH3_REGISTRATION_FRAME_ExceptionCode
Definition: pseh3_asmdef.h:11
#define inline
Definition: compat.h:23
STDMETHOD() Next(THIS_ ULONG celt, IAssociationElement *pElement, ULONG *pceltFetched) PURE
DWORD ExceptionCode
Definition: compat.h:208
DWORD ExceptionFlags
Definition: compat.h:209
struct _CONTEXT * ContextRecord
Definition: pseh3.h:34
struct _EXCEPTION_RECORD * ExceptionRecord
Definition: pseh3.h:33
PSEH3$_EXCEPTION_POINTERS volatile ExceptionPointers
Definition: pseh3.h:53
struct _SEH3$_REGISTRATION_FRAME * EndOfChain
Definition: pseh3.h:50
PSEH3$_SCOPE_TABLE ScopeTable
Definition: pseh3.h:44
unsigned long ExceptionCode
Definition: pseh3.h:60
struct _SEH3$_REGISTRATION_FRAME * Next
Definition: pseh3.h:40
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
uint32_t ULONG
Definition: typedefs.h:59
_In_ WDFIOTARGET Target
Definition: wdfrequest.h:306
_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:409
_In_ struct _KBUGCHECK_REASON_CALLBACK_RECORD * Record
Definition: ketypes.h:268
#define IS_UNWINDING(Flag)
Definition: rtltypes.h:164
#define EXCEPTION_UNWINDING
Definition: rtltypes.h:155
char CHAR
Definition: xmlstorage.h:175