- DBGKD_WAIT_STATE_CHANGE64 is used in KD protocol 5, not number 6 that we use. Proto...
[reactos.git] / reactos / lib / pseh / framebased.c
index 006a7f3..121cb90 100644 (file)
 /*
Copyright (c) 2004 KJK::Hyperion
- Permission is hereby granted, free of charge, to any person obtaining a copy of
- this software and associated documentation files (the "Software"), to deal in
- the Software without restriction, including without limitation the rights to
- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- of the Software, and to permit persons to whom the Software is furnished to do
- so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
      Copyright (c) 2004/2005 KJK::Hyperion
+
+       Permission is hereby granted, free of charge, to any person obtaining a
+       copy of this software and associated documentation files (the "Software"),
+       to deal in the Software without restriction, including without limitation
+       the rights to use, copy, modify, merge, publish, distribute, sublicense,
+       and/or sell copies of the Software, and to permit persons to whom the
      Software is furnished to do so, subject to the following conditions:
+
+       The above copyright notice and this permission notice shall be included in
      all copies or substantial portions of the Software.
+
      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+       FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      DEALINGS IN THE SOFTWARE.
 */
 
+#define _NTSYSTEM_
 #define STRICT
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 
+#include <pseh/pseh.h>
 #include <pseh/framebased/internal.h>
+#include <pseh/excpt.h>
+#include <pseh/framebased.h>
+
 #include <excpt.h>
 
+/* Tracing */
+#ifdef _SEH_ENABLE_TRACE
+extern unsigned long __cdecl DbgPrint(const char * format, ...);
+
+#define _SEH_TRACE_HEADER_(FRAME_) \
+       DbgPrint("[PSEH:%p]%s:%d:", FRAME_, __FILE__, __LINE__);
+
+#define _SEH_TRACE_TRAILER_ \
+       DbgPrint("\n");
+
+#define _SEH_FILTER_RET_STRING_(RET_) \
+       (((int)(RET_) < 0) ? "_SEH_CONTINUE_EXECUTION" : (((int)(RET_) > 0) ? "_SEH_EXECUTE_HANDLER" : "_SEH_CONTINUE_SEARCH"))
+
+#define _SEH_TRACE_LINE_(FRAME_, ARGS_) \
+{ \
+       _SEH_TRACE_HEADER_(FRAME_); \
+       DbgPrint ARGS_; \
+       _SEH_TRACE_TRAILER_; \
+}
+
+#define _SEH_TRACE_ENTER(FRAME_, FUNCNAME_, ARGS_) \
+{ \
+       if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_ENTER_LEAVE) \
+       { \
+               _SEH_TRACE_HEADER_(FRAME_); \
+               DbgPrint(">>> %s(", (FUNCNAME_)); \
+               DbgPrint ARGS_; \
+               DbgPrint(")"); \
+               _SEH_TRACE_TRAILER_; \
+       } \
+}
+
+#define _SEH_TRACE_LEAVE(FRAME_, FUNCNAME_, ARGS_) \
+{ \
+       if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_ENTER_LEAVE) \
+       { \
+               _SEH_TRACE_HEADER_(FRAME_); \
+               DbgPrint("<<< %s => ", (FUNCNAME_)); \
+               DbgPrint ARGS_; \
+               _SEH_TRACE_TRAILER_; \
+       } \
+}
+
+#define _SEH_TRACE_EXCEPTION_RECORD(FRAME_, ER_) \
+{ \
+       if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_EXCEPTION_RECORD) \
+       { \
+               _SEH_TRACE_LINE_ \
+               ( \
+                       (FRAME_), \
+                       ( \
+                               "ExceptionRecord %p = { ExceptionCode : %08X, ExceptionFlags : %08X, ExceptionRecord : %p, ExceptionAddress : %p }", \
+                               (ER_), \
+                               (ER_)->ExceptionCode, \
+                               (ER_)->ExceptionFlags, \
+                               (ER_)->ExceptionRecord, \
+                               (ER_)->ExceptionAddress \
+                       ) \
+               ); \
+       } \
+}
+
+#ifdef _X86_
+#define _SEH_TRACE_CONTEXT(FRAME_, CONTEXT_) \
+{ \
+       if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CONTEXT) \
+       { \
+               if(((CONTEXT_)->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) \
+               { \
+                       _SEH_TRACE_LINE_ \
+                       ( \
+                               (FRAME_), \
+                               ( \
+                                       "eax=%08X ebx=%08X ecx=%08X edx=%08X esi=%08X edi=%08X", \
+                                       (CONTEXT_)->Eax, \
+                                       (CONTEXT_)->Ebx, \
+                                       (CONTEXT_)->Ecx, \
+                                       (CONTEXT_)->Edx, \
+                                       (CONTEXT_)->Esi, \
+                                       (CONTEXT_)->Edi \
+                               ) \
+                       ); \
+               } \
+       \
+               if(((CONTEXT_)->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) \
+               { \
+                       _SEH_TRACE_LINE_ \
+                       ( \
+                               (FRAME_), \
+                               ( \
+                                       "eip=%08X esp=%08X ebp=%08X efl=%08X cs=%08X ss=%08X", \
+                                       (CONTEXT_)->Eip, \
+                                       (CONTEXT_)->Esp, \
+                                       (CONTEXT_)->Ebp, \
+                                       (CONTEXT_)->EFlags, \
+                                       (CONTEXT_)->SegCs, \
+                                       (CONTEXT_)->SegSs \
+                               ) \
+                       ); \
+               } \
+       \
+               if(((CONTEXT_)->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS) \
+               { \
+                       _SEH_TRACE_LINE_ \
+                       ( \
+                               (FRAME_), \
+                               ( \
+                                       "ds=%08X es=%08X fs=%08X gs=%08X", \
+                                       (CONTEXT_)->SegDs, \
+                                       (CONTEXT_)->SegEs, \
+                                       (CONTEXT_)->SegFs, \
+                                       (CONTEXT_)->SegGs \
+                               ) \
+                       ); \
+               } \
+       } \
+}
+#else
+#define _SEH_TRACE_CONTEXT(FRAME_, CONTEXT_)
+#endif
+
+#define _SEH_TRACE_UNWIND(FRAME_, ARGS_) \
+{ \
+       if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_UNWIND) \
+       { \
+               _SEH_TRACE_LINE_((FRAME_), ARGS_); \
+       } \
+}
+
+#define _SEH_TRACE_TRYLEVEL(FRAME_, TRYLEVEL_) \
+{ \
+       if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_TRYLEVEL) \
+       { \
+               _SEH_TRACE_LINE_((FRAME_), ("trylevel %p, filter %p", (TRYLEVEL_), (TRYLEVEL_)->SPT_Handlers.SH_Filter)); \
+       } \
+}
+
+#define _SEH_TRACE_ENTER_CALL_FILTER(FRAME_, TRYLEVEL_, ER_) \
+{ \
+       if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FILTER) \
+       { \
+               _SEH_TRACE_LINE_ \
+               ( \
+                       (FRAME_), \
+                       ( \
+                               "trylevel %p, calling filter %p, ExceptionCode %08X", \
+                               (TRYLEVEL_), \
+                               (TRYLEVEL_)->SPT_Handlers.SH_Filter, \
+                               (ER_)->ExceptionCode \
+                       ) \
+               ); \
+       } \
+}
+
+#define _SEH_TRACE_LEAVE_CALL_FILTER(FRAME_, TRYLEVEL_, RET_) \
+{ \
+       if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FILTER) \
+       { \
+               _SEH_TRACE_LINE_ \
+               ( \
+                       (FRAME_), \
+                       ( \
+                               "trylevel %p, filter %p => %s", \
+                               (TRYLEVEL_), \
+                               (TRYLEVEL_)->SPT_Handlers.SH_Filter, \
+                               _SEH_FILTER_RET_STRING_(RET_) \
+                       ) \
+               ); \
+       } \
+}
+
+#define _SEH_TRACE_FILTER(FRAME_, TRYLEVEL_, RET_) \
+{ \
+       if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_FILTER) \
+       { \
+               _SEH_TRACE_LINE_ \
+               ( \
+                       (FRAME_), \
+                       ( \
+                               "trylevel %p => %s", \
+                               (TRYLEVEL_), \
+                               _SEH_FILTER_RET_STRING_(RET_) \
+                       ) \
+               ); \
+       } \
+}
+
+#define _SEH_TRACE_ENTER_CALL_HANDLER(FRAME_, TRYLEVEL_) \
+{ \
+       if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_HANDLER) \
+       { \
+               _SEH_TRACE_LINE_((FRAME_), ("trylevel %p, handling", (TRYLEVEL_))); \
+       } \
+}
+
+#define _SEH_TRACE_ENTER_CALL_FINALLY(FRAME_, TRYLEVEL_) \
+{ \
+       if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FINALLY) \
+       { \
+               _SEH_TRACE_LINE_ \
+               ( \
+                       (FRAME_), \
+                       ( \
+                               "trylevel %p, calling exit routine %p", \
+                               (TRYLEVEL_), \
+                               (TRYLEVEL_)->SPT_Handlers.SH_Finally \
+                       ) \
+               ); \
+       } \
+}
+
+#define _SEH_TRACE_LEAVE_CALL_FINALLY(FRAME_, TRYLEVEL_) \
+{ \
+       if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FINALLY) \
+       { \
+               _SEH_TRACE_LINE_ \
+               ( \
+                       (FRAME_), \
+                       ( \
+                               "trylevel %p, exit routine %p returned", \
+                               (TRYLEVEL_), \
+                               (TRYLEVEL_)->SPT_Handlers.SH_Finally \
+                       ) \
+               ); \
+       } \
+}
+
+#else
+#define _SEH_TRACE_ENTER(FRAME_, FUNCNAME_, ARGS_)
+#define _SEH_TRACE_LEAVE(FRAME_, FUNCNAME_, ARGS_)
+#define _SEH_TRACE_EXCEPTION_RECORD(FRAME_, ER_)
+#define _SEH_TRACE_CONTEXT(FRAME_, CONTEXT_)
+#define _SEH_TRACE_UNWIND(FRAME_, ARGS_)
+#define _SEH_TRACE_TRYLEVEL(FRAME_, TRYLEVEL_)
+#define _SEH_TRACE_ENTER_CALL_FILTER(FRAME_, TRYLEVEL_, ER_)
+#define _SEH_TRACE_LEAVE_CALL_FILTER(FRAME_, TRYLEVEL_, RET_)
+#define _SEH_TRACE_FILTER(FRAME_, TRYLEVEL_, RET_)
+#define _SEH_TRACE_ENTER_CALL_HANDLER(FRAME_, TRYLEVEL_)
+#define _SEH_TRACE_ENTER_CALL_FINALLY(FRAME_, TRYLEVEL_)
+#define _SEH_TRACE_LEAVE_CALL_FINALLY(FRAME_, TRYLEVEL_)
+#endif
+
 /* Assembly helpers, see i386/framebased.asm */
 extern void __cdecl _SEHCleanHandlerEnvironment(void);
-extern void __cdecl _SEHRegisterFrame(_SEHRegistration_t *);
-extern void __cdecl _SEHUnregisterFrame(const _SEHRegistration_t *);
-extern void __cdecl _SEHUnwind(_SEHPortableFrame_t *);
+extern struct __SEHRegistration * __cdecl _SEHRegisterFrame(_SEHRegistration_t *);
+extern void __cdecl _SEHUnregisterFrame(void);
+extern void __cdecl _SEHGlobalUnwind(_SEHPortableFrame_t *);
+extern _SEHRegistration_t * __cdecl _SEHCurrentRegistration(void);
+
+/* Borland C++ uses a different decoration (i.e. none) for stdcall functions */
+extern void __stdcall RtlUnwind(void *, void *, PEXCEPTION_RECORD, void *);
+void const * _SEHRtlUnwind = RtlUnwind;
 
-__declspec(noreturn) void __cdecl _SEHCallHandler(_SEHPortableFrame_t * frame)
+static void __stdcall _SEHLocalUnwind
+(
+       _SEHPortableFrame_t * frame,
+       _SEHPortableTryLevel_t * dsttrylevel
+)
 {
- frame->SPF_Handling = 1;
- _SEHUnwind(frame);
- frame->SPF_Handlers->SH_Handler(frame);
+       _SEHPortableTryLevel_t * trylevel;
+
+       _SEH_TRACE_UNWIND(frame, ("enter local unwind from %p to %p", frame->SPF_TopTryLevel, dsttrylevel));
+
+       for
+       (
+               trylevel = frame->SPF_TopTryLevel;
+               trylevel != dsttrylevel;
+               trylevel = trylevel->SPT_Next
+       )
+       {
+               _SEHFinally_t pfnFinally;
+
+               /* ASSERT(trylevel); */
+
+               pfnFinally = trylevel->SPT_Handlers.SH_Finally;
+
+               if(pfnFinally)
+               {
+                       _SEH_TRACE_ENTER_CALL_FINALLY(frame, trylevel);
+                       pfnFinally(frame);
+                       _SEH_TRACE_LEAVE_CALL_FINALLY(frame, trylevel);
+               }
+       }
+
+       _SEH_TRACE_UNWIND(frame, ("leave local unwind from %p to %p", frame->SPF_TopTryLevel, dsttrylevel));
+}
+
+static void __cdecl _SEHCallHandler
+(
+       _SEHPortableFrame_t * frame,
+       _SEHPortableTryLevel_t * trylevel
+)
+{
+       _SEHGlobalUnwind(frame);
+       _SEHLocalUnwind(frame, trylevel);
+       _SEH_TRACE_ENTER_CALL_HANDLER(frame, trylevel);
+       frame->SPF_Handler(trylevel);
+       /* ASSERT(0); */
 }
 
-int __cdecl _SEHFrameHandler
+static int __cdecl _SEHFrameHandler
 (
- struct _EXCEPTION_RECORD * ExceptionRecord,
- void * EstablisherFrame,
- struct _CONTEXT * ContextRecord,
- void * DispatcherContext
      struct _EXCEPTION_RECORD * ExceptionRecord,
      void * EstablisherFrame,
      struct _CONTEXT * ContextRecord,
      void * DispatcherContext
 )
 {
- _SEHPortableFrame_t * frame;
-
- _SEHCleanHandlerEnvironment();
-
- frame = EstablisherFrame;
-
- /* Unwinding */
- if(ExceptionRecord->ExceptionFlags & (4 | 2))
- {
-  if(frame->SPF_Handlers->SH_Finally && !frame->SPF_Handling)
-   frame->SPF_Handlers->SH_Finally(frame);
- }
- /* Handling */
- else
- {
-  if(ExceptionRecord->ExceptionCode)
-   frame->SPF_Code = ExceptionRecord->ExceptionCode;
-  else
-   frame->SPF_Code = 0xC0000001; 
-
-  if(frame->SPF_Handlers->SH_Filter)
-  {
-   int ret;
-
-   switch((UINT_PTR)frame->SPF_Handlers->SH_Filter)
-   {
-    case EXCEPTION_EXECUTE_HANDLER + 1:
-    case EXCEPTION_CONTINUE_SEARCH + 1:
-    case EXCEPTION_CONTINUE_EXECUTION + 1:
-    {
-     ret = (int)((UINT_PTR)frame->SPF_Handlers->SH_Filter) - 1;
-     break;
-    }
-
-    default:
-    {
-     EXCEPTION_POINTERS ep;
-
-     ep.ExceptionRecord = ExceptionRecord;
-     ep.ContextRecord = ContextRecord;
-
-     ret = frame->SPF_Handlers->SH_Filter(&ep, frame);
-     break;
-    }
-   }
-
-   /* EXCEPTION_CONTINUE_EXECUTION */
-   if(ret < 0)
-    return ExceptionContinueExecution;
-   /* EXCEPTION_EXECUTE_HANDLER */
-   else if(ret > 0)
-    _SEHCallHandler(frame);
-   /* EXCEPTION_CONTINUE_SEARCH */
-   else
-    /* fall through */;
-  }
- }
-
- return ExceptionContinueSearch;
-}
-
-void __stdcall _SEHEnter(_SEHPortableFrame_t * frame)
+       _SEHPortableFrame_t * frame;
+
+       _SEHCleanHandlerEnvironment();
+
+       frame = EstablisherFrame;
+
+       _SEH_TRACE_ENTER
+       (
+               frame,
+               "_SEHFrameHandler",
+               (
+                       "%p, %p, %p, %p",
+                       ExceptionRecord,
+                       EstablisherFrame,
+                       ContextRecord,
+                       DispatcherContext
+               )
+       );
+
+       _SEH_TRACE_EXCEPTION_RECORD(frame, ExceptionRecord);
+       _SEH_TRACE_CONTEXT(frame, ContextRecord);
+
+       /* Unwinding */
+       if(ExceptionRecord->ExceptionFlags & (4 | 2))
+       {
+               _SEH_TRACE_UNWIND(frame, ("enter forced unwind"));
+               _SEHLocalUnwind(frame, NULL);
+               _SEH_TRACE_UNWIND(frame, ("leave forced unwind"));
+       }
+       /* Handling */
+       else
+       {
+               int ret;
+               _SEHPortableTryLevel_t * trylevel;
+
+               if(ExceptionRecord->ExceptionCode)
+                       frame->SPF_Code = ExceptionRecord->ExceptionCode;
+               else
+                       frame->SPF_Code = 0xC0000001;
+
+               for
+               (
+                       trylevel = frame->SPF_TopTryLevel;
+                       trylevel != NULL;
+                       trylevel = trylevel->SPT_Next
+               )
+               {
+                       _SEHFilter_t pfnFilter = trylevel->SPT_Handlers.SH_Filter;
+
+                       _SEH_TRACE_TRYLEVEL(frame, trylevel);
+
+                       switch((UINT_PTR)pfnFilter)
+                       {
+                               case (UINT_PTR)_SEH_STATIC_FILTER(_SEH_EXECUTE_HANDLER):
+                               case (UINT_PTR)_SEH_STATIC_FILTER(_SEH_CONTINUE_SEARCH):
+                               case (UINT_PTR)_SEH_STATIC_FILTER(_SEH_CONTINUE_EXECUTION):
+                               {
+                                       ret = (int)((UINT_PTR)pfnFilter) - 2;
+                                       break;
+                               }
+
+                               default:
+                               {
+                                       if(trylevel->SPT_Handlers.SH_Filter)
+                                       {
+                                               EXCEPTION_POINTERS ep;
+
+                                               ep.ExceptionRecord = ExceptionRecord;
+                                               ep.ContextRecord = ContextRecord;
+
+                                               _SEH_TRACE_ENTER_CALL_FILTER(frame, trylevel, ExceptionRecord);
+                                               ret = pfnFilter(&ep, frame);
+                                               _SEH_TRACE_LEAVE_CALL_FILTER(frame, trylevel, ret);
+                                       }
+                                       else
+                                               ret = _SEH_CONTINUE_SEARCH;
+
+                                       break;
+                               }
+                       }
+
+                       _SEH_TRACE_FILTER(frame, trylevel, ret);
+
+                       /* _SEH_CONTINUE_EXECUTION */
+                       if(ret < 0)
+                       {
+                               _SEH_TRACE_LEAVE(frame, "_SEHFrameHandler", ("ExceptionContinueExecution"));
+                               return ExceptionContinueExecution;
+                       }
+                       /* _SEH_EXECUTE_HANDLER */
+                       else if(ret > 0)
+                               _SEHCallHandler(frame, trylevel);
+                       /* _SEH_CONTINUE_SEARCH */
+                       else
+                               continue;
+               }
+
+               /* FALLTHROUGH */
+       }
+
+       _SEH_TRACE_LEAVE(frame, "_SEHFrameHandler", ("ExceptionContinueSearch"));
+       return ExceptionContinueSearch;
+}
+
+void __stdcall _SEHEnterFrame_s(_SEHPortableFrame_t * frame)
+{
+       _SEHEnterFrame_f(frame);
+}
+
+void __stdcall _SEHLeaveFrame_s(void)
 {
- frame->SPF_Registration.SER_Handler = _SEHFrameHandler;
- frame->SPF_Code = 0;
- frame->SPF_Handling = 0;
- _SEHRegisterFrame(&frame->SPF_Registration);
+       _SEHLeaveFrame_f();
 }
 
-void __stdcall _SEHLeave(_SEHPortableFrame_t * frame)
+void __stdcall _SEHReturn_s(void)
 {
- _SEHUnregisterFrame(&frame->SPF_Registration);
+       _SEHReturn_f();
+}
+
+void _SEH_FASTCALL _SEHEnterFrame_f(_SEHPortableFrame_t * frame)
+{
+       /* ASSERT(frame); */
+       /* ASSERT(trylevel); */
+       frame->SPF_Registration.SER_Handler = _SEHFrameHandler;
+       frame->SPF_Code = 0;
+       _SEHRegisterFrame(&frame->SPF_Registration);
+}
+
+void _SEH_FASTCALL _SEHLeaveFrame_f(void)
+{
+       _SEHPortableFrame_t * frame;
+
+       frame = _SEH_CONTAINING_RECORD
+       (
+               _SEHCurrentRegistration(),
+               _SEHPortableFrame_t,
+               SPF_Registration
+       );
+
+       /* ASSERT(frame); */
+       /* ASSERT(frame->SPF_TopTryLevel == NULL) */
+
+       _SEHUnregisterFrame();
+}
+
+void _SEH_FASTCALL _SEHReturn_f(void)
+{
+       _SEHPortableFrame_t * frame;
+
+       frame = _SEH_CONTAINING_RECORD
+       (
+               _SEHCurrentRegistration(),
+               _SEHPortableFrame_t,
+               SPF_Registration
+       );
+
+       _SEHLocalUnwind(frame, NULL);
+       _SEHUnregisterFrame();
 }
 
 /* EOF */