- Move NCI generated files to arch-specific directories
[reactos.git] / reactos / lib / pseh / framebased.c
1 /*
2 Copyright (c) 2004/2005 KJK::Hyperion
3
4 Permission is hereby granted, free of charge, to any person obtaining a
5 copy of this software and associated documentation files (the "Software"),
6 to deal in the Software without restriction, including without limitation
7 the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 and/or sell copies of the Software, and to permit persons to whom the
9 Software is furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 DEALINGS IN THE SOFTWARE.
21 */
22
23 #define STRICT
24 #define WIN32_LEAN_AND_MEAN
25 #include <windows.h>
26
27 #include <pseh/pseh.h>
28 #include <pseh/framebased/internal.h>
29 #include <pseh/excpt.h>
30 #include <pseh/framebased.h>
31
32 #include <excpt.h>
33
34 /* Tracing */
35 #ifdef _SEH_ENABLE_TRACE
36 extern unsigned long __cdecl DbgPrint(const char * format, ...);
37
38 #define _SEH_TRACE_HEADER_(FRAME_) \
39 DbgPrint("[PSEH:%p]%s:%d:", FRAME_, __FILE__, __LINE__);
40
41 #define _SEH_TRACE_TRAILER_ \
42 DbgPrint("\n");
43
44 #define _SEH_FILTER_RET_STRING_(RET_) \
45 (((int)(RET_) < 0) ? "_SEH_CONTINUE_EXECUTION" : (((int)(RET_) > 0) ? "_SEH_EXECUTE_HANDLER" : "_SEH_CONTINUE_SEARCH"))
46
47 #define _SEH_TRACE_LINE_(FRAME_, ARGS_) \
48 { \
49 _SEH_TRACE_HEADER_(FRAME_); \
50 DbgPrint ARGS_; \
51 _SEH_TRACE_TRAILER_; \
52 }
53
54 #define _SEH_TRACE_ENTER(FRAME_, FUNCNAME_, ARGS_) \
55 { \
56 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_ENTER_LEAVE) \
57 { \
58 _SEH_TRACE_HEADER_(FRAME_); \
59 DbgPrint(">>> %s(", (FUNCNAME_)); \
60 DbgPrint ARGS_; \
61 DbgPrint(")"); \
62 _SEH_TRACE_TRAILER_; \
63 } \
64 }
65
66 #define _SEH_TRACE_LEAVE(FRAME_, FUNCNAME_, ARGS_) \
67 { \
68 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_ENTER_LEAVE) \
69 { \
70 _SEH_TRACE_HEADER_(FRAME_); \
71 DbgPrint("<<< %s => ", (FUNCNAME_)); \
72 DbgPrint ARGS_; \
73 _SEH_TRACE_TRAILER_; \
74 } \
75 }
76
77 #define _SEH_TRACE_EXCEPTION_RECORD(FRAME_, ER_) \
78 { \
79 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_EXCEPTION_RECORD) \
80 { \
81 _SEH_TRACE_LINE_ \
82 ( \
83 (FRAME_), \
84 ( \
85 "ExceptionRecord %p = { ExceptionCode : %08X, ExceptionFlags : %08X, ExceptionRecord : %p, ExceptionAddress : %p }", \
86 (ER_), \
87 (ER_)->ExceptionCode, \
88 (ER_)->ExceptionFlags, \
89 (ER_)->ExceptionRecord, \
90 (ER_)->ExceptionAddress \
91 ) \
92 ); \
93 } \
94 }
95
96 #ifdef _X86_
97 #define _SEH_TRACE_CONTEXT(FRAME_, CONTEXT_) \
98 { \
99 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CONTEXT) \
100 { \
101 if(((CONTEXT_)->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) \
102 { \
103 _SEH_TRACE_LINE_ \
104 ( \
105 (FRAME_), \
106 ( \
107 "eax=%08X ebx=%08X ecx=%08X edx=%08X esi=%08X edi=%08X", \
108 (CONTEXT_)->Eax, \
109 (CONTEXT_)->Ebx, \
110 (CONTEXT_)->Ecx, \
111 (CONTEXT_)->Edx, \
112 (CONTEXT_)->Esi, \
113 (CONTEXT_)->Edi \
114 ) \
115 ); \
116 } \
117 \
118 if(((CONTEXT_)->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) \
119 { \
120 _SEH_TRACE_LINE_ \
121 ( \
122 (FRAME_), \
123 ( \
124 "eip=%08X esp=%08X ebp=%08X efl=%08X cs=%08X ss=%08X", \
125 (CONTEXT_)->Eip, \
126 (CONTEXT_)->Esp, \
127 (CONTEXT_)->Ebp, \
128 (CONTEXT_)->EFlags, \
129 (CONTEXT_)->SegCs, \
130 (CONTEXT_)->SegSs \
131 ) \
132 ); \
133 } \
134 \
135 if(((CONTEXT_)->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS) \
136 { \
137 _SEH_TRACE_LINE_ \
138 ( \
139 (FRAME_), \
140 ( \
141 "ds=%08X es=%08X fs=%08X gs=%08X", \
142 (CONTEXT_)->SegDs, \
143 (CONTEXT_)->SegEs, \
144 (CONTEXT_)->SegFs, \
145 (CONTEXT_)->SegGs \
146 ) \
147 ); \
148 } \
149 } \
150 }
151 #else
152 #error Unsupported platform.
153 #endif
154
155 #define _SEH_TRACE_UNWIND(FRAME_, ARGS_) \
156 { \
157 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_UNWIND) \
158 { \
159 _SEH_TRACE_LINE_((FRAME_), ARGS_); \
160 } \
161 }
162
163 #define _SEH_TRACE_TRYLEVEL(FRAME_, TRYLEVEL_) \
164 { \
165 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_TRYLEVEL) \
166 { \
167 _SEH_TRACE_LINE_((FRAME_), ("trylevel %p, filter %p", (TRYLEVEL_), (TRYLEVEL_)->SPT_Handlers->SH_Filter)); \
168 } \
169 }
170
171 #define _SEH_TRACE_ENTER_CALL_FILTER(FRAME_, TRYLEVEL_, ER_) \
172 { \
173 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FILTER) \
174 { \
175 _SEH_TRACE_LINE_ \
176 ( \
177 (FRAME_), \
178 ( \
179 "trylevel %p, calling filter %p, ExceptionCode %08X", \
180 (TRYLEVEL_), \
181 (TRYLEVEL_)->SPT_Handlers->SH_Filter, \
182 (ER_)->ExceptionCode \
183 ) \
184 ); \
185 } \
186 }
187
188 #define _SEH_TRACE_LEAVE_CALL_FILTER(FRAME_, TRYLEVEL_, RET_) \
189 { \
190 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FILTER) \
191 { \
192 _SEH_TRACE_LINE_ \
193 ( \
194 (FRAME_), \
195 ( \
196 "trylevel %p, filter %p => %s", \
197 (TRYLEVEL_), \
198 (TRYLEVEL_)->SPT_Handlers->SH_Filter, \
199 _SEH_FILTER_RET_STRING_(RET_) \
200 ) \
201 ); \
202 } \
203 }
204
205 #define _SEH_TRACE_FILTER(FRAME_, TRYLEVEL_, RET_) \
206 { \
207 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_FILTER) \
208 { \
209 _SEH_TRACE_LINE_ \
210 ( \
211 (FRAME_), \
212 ( \
213 "trylevel %p => %s", \
214 (TRYLEVEL_), \
215 _SEH_FILTER_RET_STRING_(RET_) \
216 ) \
217 ); \
218 } \
219 }
220
221 #define _SEH_TRACE_ENTER_CALL_HANDLER(FRAME_, TRYLEVEL_) \
222 { \
223 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_HANDLER) \
224 { \
225 _SEH_TRACE_LINE_((FRAME_), ("trylevel %p, handling", (TRYLEVEL_))); \
226 } \
227 }
228
229 #define _SEH_TRACE_ENTER_CALL_FINALLY(FRAME_, TRYLEVEL_) \
230 { \
231 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FINALLY) \
232 { \
233 _SEH_TRACE_LINE_ \
234 ( \
235 (FRAME_), \
236 ( \
237 "trylevel %p, calling exit routine %p", \
238 (TRYLEVEL_), \
239 (TRYLEVEL_)->SPT_Handlers->SH_Finally \
240 ) \
241 ); \
242 } \
243 }
244
245 #define _SEH_TRACE_LEAVE_CALL_FINALLY(FRAME_, TRYLEVEL_) \
246 { \
247 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FINALLY) \
248 { \
249 _SEH_TRACE_LINE_ \
250 ( \
251 (FRAME_), \
252 ( \
253 "trylevel %p, exit routine %p returned", \
254 (TRYLEVEL_), \
255 (TRYLEVEL_)->SPT_Handlers->SH_Finally \
256 ) \
257 ); \
258 } \
259 }
260
261 #else
262 #define _SEH_TRACE_ENTER(FRAME_, FUNCNAME_, ARGS_)
263 #define _SEH_TRACE_LEAVE(FRAME_, FUNCNAME_, ARGS_)
264 #define _SEH_TRACE_EXCEPTION_RECORD(FRAME_, ER_)
265 #define _SEH_TRACE_CONTEXT(FRAME_, CONTEXT_)
266 #define _SEH_TRACE_UNWIND(FRAME_, ARGS_)
267 #define _SEH_TRACE_TRYLEVEL(FRAME_, TRYLEVEL_)
268 #define _SEH_TRACE_ENTER_CALL_FILTER(FRAME_, TRYLEVEL_, ER_)
269 #define _SEH_TRACE_LEAVE_CALL_FILTER(FRAME_, TRYLEVEL_, RET_)
270 #define _SEH_TRACE_FILTER(FRAME_, TRYLEVEL_, RET_)
271 #define _SEH_TRACE_ENTER_CALL_HANDLER(FRAME_, TRYLEVEL_)
272 #define _SEH_TRACE_ENTER_CALL_FINALLY(FRAME_, TRYLEVEL_)
273 #define _SEH_TRACE_LEAVE_CALL_FINALLY(FRAME_, TRYLEVEL_)
274 #endif
275
276 /* Assembly helpers, see i386/framebased.asm */
277 extern void __cdecl _SEHCleanHandlerEnvironment(void);
278 extern struct __SEHRegistration * __cdecl _SEHRegisterFrame(_SEHRegistration_t *);
279 extern void __cdecl _SEHUnregisterFrame(void);
280 extern void __cdecl _SEHGlobalUnwind(_SEHPortableFrame_t *);
281 extern _SEHRegistration_t * __cdecl _SEHCurrentRegistration(void);
282
283 /* Borland C++ uses a different decoration (i.e. none) for stdcall functions */
284 extern void __stdcall RtlUnwind(void *, void *, void *, void *);
285 void const * _SEHRtlUnwind = RtlUnwind;
286
287 static void __stdcall _SEHLocalUnwind
288 (
289 _SEHPortableFrame_t * frame,
290 _SEHPortableTryLevel_t * dsttrylevel
291 )
292 {
293 _SEHPortableTryLevel_t * trylevel;
294
295 _SEH_TRACE_UNWIND(frame, ("enter local unwind from %p to %p", frame->SPF_TopTryLevel, dsttrylevel));
296
297 for
298 (
299 trylevel = frame->SPF_TopTryLevel;
300 trylevel != dsttrylevel;
301 trylevel = trylevel->SPT_Next
302 )
303 {
304 _SEHFinally_t pfnFinally;
305
306 /* ASSERT(trylevel); */
307
308 pfnFinally = trylevel->SPT_Handlers->SH_Finally;
309
310 if(pfnFinally)
311 {
312 _SEH_TRACE_ENTER_CALL_FINALLY(frame, trylevel);
313 pfnFinally(frame);
314 _SEH_TRACE_LEAVE_CALL_FINALLY(frame, trylevel);
315 }
316 }
317
318 _SEH_TRACE_UNWIND(frame, ("leave local unwind from %p to %p", frame->SPF_TopTryLevel, dsttrylevel));
319 }
320
321 static void __cdecl _SEHCallHandler
322 (
323 _SEHPortableFrame_t * frame,
324 _SEHPortableTryLevel_t * trylevel
325 )
326 {
327 _SEHGlobalUnwind(frame);
328 _SEHLocalUnwind(frame, trylevel);
329 _SEH_TRACE_ENTER_CALL_HANDLER(frame, trylevel);
330 frame->SPF_Handler(trylevel);
331 /* ASSERT(0); */
332 }
333
334 static int __cdecl _SEHFrameHandler
335 (
336 struct _EXCEPTION_RECORD * ExceptionRecord,
337 void * EstablisherFrame,
338 struct _CONTEXT * ContextRecord,
339 void * DispatcherContext
340 )
341 {
342 _SEHPortableFrame_t * frame;
343
344 _SEHCleanHandlerEnvironment();
345
346 frame = EstablisherFrame;
347
348 _SEH_TRACE_ENTER
349 (
350 frame,
351 "_SEHFrameHandler",
352 (
353 "%p, %p, %p, %p",
354 ExceptionRecord,
355 EstablisherFrame,
356 ContextRecord,
357 DispatcherContext
358 )
359 );
360
361 _SEH_TRACE_EXCEPTION_RECORD(frame, ExceptionRecord);
362 _SEH_TRACE_CONTEXT(frame, ContextRecord);
363
364 /* Unwinding */
365 if(ExceptionRecord->ExceptionFlags & (4 | 2))
366 {
367 _SEH_TRACE_UNWIND(frame, ("enter forced unwind"));
368 _SEHLocalUnwind(frame, NULL);
369 _SEH_TRACE_UNWIND(frame, ("leave forced unwind"));
370 }
371 /* Handling */
372 else
373 {
374 int ret;
375 _SEHPortableTryLevel_t * trylevel;
376
377 if(ExceptionRecord->ExceptionCode)
378 frame->SPF_Code = ExceptionRecord->ExceptionCode;
379 else
380 frame->SPF_Code = 0xC0000001;
381
382 for
383 (
384 trylevel = frame->SPF_TopTryLevel;
385 trylevel != NULL;
386 trylevel = trylevel->SPT_Next
387 )
388 {
389 _SEHFilter_t pfnFilter = trylevel->SPT_Handlers->SH_Filter;
390
391 _SEH_TRACE_TRYLEVEL(frame, trylevel);
392
393 switch((UINT_PTR)pfnFilter)
394 {
395 case (UINT_PTR)_SEH_STATIC_FILTER(_SEH_EXECUTE_HANDLER):
396 case (UINT_PTR)_SEH_STATIC_FILTER(_SEH_CONTINUE_SEARCH):
397 case (UINT_PTR)_SEH_STATIC_FILTER(_SEH_CONTINUE_EXECUTION):
398 {
399 ret = (int)((UINT_PTR)pfnFilter) - 2;
400 break;
401 }
402
403 default:
404 {
405 if(trylevel->SPT_Handlers->SH_Filter)
406 {
407 EXCEPTION_POINTERS ep;
408
409 ep.ExceptionRecord = ExceptionRecord;
410 ep.ContextRecord = ContextRecord;
411
412 _SEH_TRACE_ENTER_CALL_FILTER(frame, trylevel, ExceptionRecord);
413 ret = pfnFilter(&ep, frame);
414 _SEH_TRACE_LEAVE_CALL_FILTER(frame, trylevel, ret);
415 }
416 else
417 ret = _SEH_CONTINUE_SEARCH;
418
419 break;
420 }
421 }
422
423 _SEH_TRACE_FILTER(frame, trylevel, ret);
424
425 /* _SEH_CONTINUE_EXECUTION */
426 if(ret < 0)
427 {
428 _SEH_TRACE_LEAVE(frame, "_SEHFrameHandler", ("ExceptionContinueExecution"));
429 return ExceptionContinueExecution;
430 }
431 /* _SEH_EXECUTE_HANDLER */
432 else if(ret > 0)
433 _SEHCallHandler(frame, trylevel);
434 /* _SEH_CONTINUE_SEARCH */
435 else
436 continue;
437 }
438
439 /* FALLTHROUGH */
440 }
441
442 _SEH_TRACE_LEAVE(frame, "_SEHFrameHandler", ("ExceptionContinueSearch"));
443 return ExceptionContinueSearch;
444 }
445
446 void __stdcall _SEHEnterFrame_s
447 (
448 _SEHPortableFrame_t * frame,
449 _SEHPortableTryLevel_t * trylevel
450 )
451 {
452 _SEHEnterFrame_f(frame, trylevel);
453 }
454
455 void __stdcall _SEHEnterTry_s(_SEHPortableTryLevel_t * trylevel)
456 {
457 _SEHEnterTry_f(trylevel);
458 }
459
460 void __stdcall _SEHLeave_s(void)
461 {
462 _SEHLeave_f();
463 }
464
465 void _SEH_FASTCALL _SEHEnterFrame_f
466 (
467 _SEHPortableFrame_t * frame,
468 _SEHPortableTryLevel_t * trylevel
469 )
470 {
471 /* ASSERT(frame); */
472 /* ASSERT(trylevel); */
473 frame->SPF_Registration.SER_Handler = _SEHFrameHandler;
474 frame->SPF_Code = 0;
475 frame->SPF_TopTryLevel = trylevel;
476 trylevel->SPT_Next = NULL;
477 _SEHRegisterFrame(&frame->SPF_Registration);
478 }
479
480 void _SEH_FASTCALL _SEHEnterTry_f(_SEHPortableTryLevel_t * trylevel)
481 {
482 _SEHPortableFrame_t * frame;
483
484 frame = _SEH_CONTAINING_RECORD
485 (
486 _SEHCurrentRegistration(),
487 _SEHPortableFrame_t,
488 SPF_Registration
489 );
490
491 trylevel->SPT_Next = frame->SPF_TopTryLevel;
492 frame->SPF_TopTryLevel = trylevel;
493 }
494
495 void _SEH_FASTCALL _SEHLeave_f(void)
496 {
497 _SEHPortableFrame_t * frame;
498 _SEHPortableTryLevel_t * trylevel;
499
500 frame = _SEH_CONTAINING_RECORD
501 (
502 _SEHCurrentRegistration(),
503 _SEHPortableFrame_t,
504 SPF_Registration
505 );
506
507 /* ASSERT(frame); */
508
509 trylevel = frame->SPF_TopTryLevel;
510
511 /* ASSERT(trylevel); */
512
513 if(trylevel->SPT_Next)
514 frame->SPF_TopTryLevel = trylevel->SPT_Next;
515 else
516 _SEHUnregisterFrame();
517 }
518
519 /* EOF */