ReactOS 0.4.15-dev-7674-gc0b4db1
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
63void
64__attribute__((regparm(1)))
65_SEH3$_Unregister(
67{
68 if (Frame->Handler)
69 _SEH3$_UnregisterFrame(Frame);
70 else
71 _SEH3$_UnregisterTryLevel(Frame);
72}
73
74static inline
75LONG
77 volatile SEH3$_REGISTRATION_FRAME *RegistrationFrame,
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
103long
104__attribute__((regparm(1)))
105_SEH3$_InvokeEmbeddedFilter(
106 volatile SEH3$_REGISTRATION_FRAME *RegistrationFrame);
107
108long
109__attribute__((regparm(1)))
110_SEH3$_InvokeEmbeddedFilterFromRegistration(
111 volatile SEH3$_REGISTRATION_FRAME *RegistrationFrame);
112
113static inline
114LONG
115_SEH3$_InvokeFilter(
116 volatile SEH3$_REGISTRATION_FRAME *RegistrationFrame,
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
143void
144__attribute__((regparm(1)))
145_SEH3$_AutoCleanup(
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
161static inline
162LONG
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 */
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
193static inline
194VOID
197{
198 _SEH3$_InvokeFilter(Record, Record->ScopeTable->Filter);
199}
200
201__attribute__((noreturn))
202static inline
203void
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
251void
254 PSEH3$_REGISTRATION_FRAME RegistrationFrame);
255
256
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
#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 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
enum _EXCEPTION_DISPOSITION EXCEPTION_DISPOSITION
_Must_inspect_result_ _In_opt_ PFLT_FILTER Filter
Definition: fltkernel.h:1801
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
#define EXCEPTION_CONTINUE_SEARCH
Definition: excpt.h:86
#define EXCEPTION_CONTINUE_EXECUTION
Definition: excpt.h:87
#define C_ASSERT(e)
Definition: intsafe.h:73
#define __fastcall
Definition: sync.c:38
_IRQL_requires_same_ _In_ PVOID EstablisherFrame
Definition: ntbasedef.h:653
_IRQL_requires_same_ _In_ PVOID _Inout_ struct _CONTEXT * ContextRecord
Definition: ntbasedef.h:654
_IRQL_requires_same_ _In_ PVOID _Inout_ struct _CONTEXT _In_ PVOID DispatcherContext
Definition: ntbasedef.h:655
long LONG
Definition: pedump.c:60
#define volatile
Definition: prototyp.h:117
void __fastcall _SEH3$_CallRtlUnwind(PSEH3$_REGISTRATION_FRAME RegistrationFrame)
static VOID _SEH3$_CallFinally(PSEH3$_REGISTRATION_FRAME Record)
Definition: pseh3.c:195
static LONG _SEH3$_GetFilterResult(PSEH3$_REGISTRATION_FRAME Record)
Definition: pseh3.c:163
static LONG _SEH3$_InvokeNestedFunctionFilter(volatile SEH3$_REGISTRATION_FRAME *RegistrationFrame, PVOID Filter)
Definition: pseh3.c:76
int const SEH3$_SCOPE_TABLE void * AllocaFrame
Definition: pseh3.h:128
int const SEH3$_SCOPE_TABLE * ScopeTable
Definition: pseh3.h:127
@ _SEH3$_CLANG_HANDLER
Definition: pseh3.h:28
@ _SEH3$_CPP_HANDLER
Definition: pseh3.h:27
@ _SEH3$_NESTED_HANDLER
Definition: pseh3.h:26
#define SEH3_REGISTRATION_FRAME_AllocaFrame
Definition: pseh3_asmdef.h:11
#define SEH3_REGISTRATION_FRAME_ExceptionPointers
Definition: pseh3_asmdef.h:7
#define SEH3_SCOPE_TABLE_Target
Definition: pseh3_asmdef.h:17
#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:5
#define SEH3_REGISTRATION_FRAME_Ebp
Definition: pseh3_asmdef.h:10
#define SEH3_SCOPE_TABLE_Filter
Definition: pseh3_asmdef.h:18
#define SEH3_REGISTRATION_FRAME_Edi
Definition: pseh3_asmdef.h:14
#define SEH3_REGISTRATION_FRAME_Esi
Definition: pseh3_asmdef.h:13
#define SEH3_REGISTRATION_FRAME_ReturnAddress
Definition: pseh3_asmdef.h:15
#define SEH3_REGISTRATION_FRAME_Next
Definition: pseh3_asmdef.h:3
#define SEH3_REGISTRATION_FRAME_ScopeTable
Definition: pseh3_asmdef.h:6
#define SEH3_REGISTRATION_FRAME_Ebx
Definition: pseh3_asmdef.h:12
#define SEH3_REGISTRATION_FRAME_ExceptionCode
Definition: pseh3_asmdef.h:8
#define inline
Definition: compat.h:23
DWORD ExceptionCode
Definition: compat.h:208
DWORD ExceptionFlags
Definition: compat.h:209
struct _CONTEXT * ContextRecord
Definition: pseh3.h:49
struct _EXCEPTION_RECORD * ExceptionRecord
Definition: pseh3.h:48
PSEH3$_EXCEPTION_POINTERS volatile ExceptionPointers
Definition: pseh3.h:65
struct _SEH3$_REGISTRATION_FRAME * EndOfChain
Definition: pseh3.h:59
PSEH3$_SCOPE_TABLE ScopeTable
Definition: pseh3.h:62
unsigned long ExceptionCode
Definition: pseh3.h:68
struct _SEH3$_REGISTRATION_FRAME * Next
Definition: pseh3.h:55
#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 EXCEPTION_UNWINDING
Definition: rtltypes.h:155
char CHAR
Definition: xmlstorage.h:175