add a little more debug output in case of unhandled exceptions
[reactos.git] / reactos / lib / kernel32 / except / except.c
index c5e4b35..c5a76ff 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: except.c,v 1.9 2002/09/08 10:22:41 chorns Exp $
+/* $Id: except.c,v 1.17 2004/09/26 16:54:53 royce Exp $
  *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS system libraries
  *                  Created 01/11/98
  */
 
-#include <ddk/ntddk.h>
-#include <windows.h>
-
-#include <kernel32/error.h>
-
-typedef LONG (STDCALL *LPTOP_LEVEL_EXCEPTION_FILTER)(
-       struct _EXCEPTION_POINTERS *ExceptionInfo
-       );
-
-UINT GlobalErrMode;
-LPTOP_LEVEL_EXCEPTION_FILTER GlobalTopLevelExceptionFilter;
-
-UINT GetErrorMode(void);
+#include <k32.h>
 
+#define NDEBUG
+#include "../include/debug.h"
 
+UINT GlobalErrMode = 0;
+LPTOP_LEVEL_EXCEPTION_FILTER GlobalTopLevelExceptionFilter = NULL;
 
 UINT GetErrorMode(void)
 {
        return GlobalErrMode;
 }
 
+
+/*
+ * @implemented
+ */
 UINT 
 STDCALL
 SetErrorMode(  UINT uMode  )
@@ -40,6 +36,10 @@ SetErrorMode(  UINT uMode  )
        return OldErrMode;
 }
 
+
+/*
+ * @implemented
+ */
 LPTOP_LEVEL_EXCEPTION_FILTER
 STDCALL
 SetUnhandledExceptionFilter(
@@ -48,56 +48,139 @@ SetUnhandledExceptionFilter(
 {
     LPTOP_LEVEL_EXCEPTION_FILTER OldTopLevelExceptionFilter =
                                         GlobalTopLevelExceptionFilter;
-    lpTopLevelExceptionFilter = GlobalTopLevelExceptionFilter;
+    GlobalTopLevelExceptionFilter = lpTopLevelExceptionFilter;
     return OldTopLevelExceptionFilter;
 }
 
 
-LONG
-STDCALL
-UnhandledExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo)
+/*
+ * Private helper function to lookup the module name from a given address.
+ * The address can point to anywhere within the module.
+ */
+static const char*
+_module_name_from_addr(const void* addr, char* psz, size_t nChars)
 {
-       DWORD   dbgRet;
-       HANDLE DebugPort;
-       NTSTATUS errCode;
-
-       if(ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION) {
-               // might check read only resource
-               // Is there a debugger running ?
-               errCode = NtQueryInformationProcess(NtCurrentProcess(),ProcessDebugPort,&DebugPort,sizeof(HANDLE),NULL);
-               if ( !NT_SUCCESS(errCode) ) {
-                       SetLastErrorByStatus(errCode);
-                       return EXCEPTION_EXECUTE_HANDLER;
-               }
-               if ( DebugPort ) {
-                       //return EXCEPTION_CONTINUE_SEARCH;
-               }
-               if(GlobalTopLevelExceptionFilter != NULL) {
-               dbgRet = GlobalTopLevelExceptionFilter(ExceptionInfo);
-               if(dbgRet == EXCEPTION_EXECUTE_HANDLER) 
-                       return EXCEPTION_EXECUTE_HANDLER;
-               else if(dbgRet == EXCEPTION_CONTINUE_EXECUTION) 
-                       return EXCEPTION_CONTINUE_EXECUTION;
-               }
+   MEMORY_BASIC_INFORMATION mbi;
+   if (VirtualQuery(addr, &mbi, sizeof(mbi)) != sizeof(mbi) ||
+       !GetModuleFileNameA((HMODULE)mbi.AllocationBase, psz, nChars))
+   {
+      psz[0] = '\0';
+   }
+   return psz;
+}
 
-       }
+static VOID
+_dump_context(PCONTEXT pc)
+{
+   /*
+    * Print out the CPU registers
+    */
+   DbgPrint("CS:EIP %x:%x\n", pc->SegCs&0xffff, pc->Eip );
+   DbgPrint("DS %x ES %x FS %x GS %x\n", pc->SegDs&0xffff, pc->SegEs&0xffff,
+           pc->SegFs&0xffff, pc->SegGs&0xfff);
+   DbgPrint("EAX: %.8x   EBX: %.8x   ECX: %.8x\n", pc->Eax, pc->Ebx, pc->Ecx);
+   DbgPrint("EDX: %.8x   EBP: %.8x   ESI: %.8x   ESP: %.8x\n", pc->Edx,
+           pc->Ebp, pc->Esi, pc->Esp);
+   DbgPrint("EDI: %.8x   EFLAGS: %.8x\n", pc->Edi, pc->EFlags);
+}
 
-       //if ( GetErrorMode() & SEM_NOGPFAULTERRORBOX == SEM_NOGPFAULTERRORBOX ) {
-               // produce a stack trace or pop a message
-               //sprintf( message, "Unhandled exception 0x%08lx at address 0x%08lx.",
-               //      ExceptionInfo->ExceptionRecord->ExceptionCode,
-               //      (DWORD)ExceptionInfo->ExceptionRecord->ExceptionAddress );
-               //MessageBoxA( 0, message, "Error", MB_OK | MB_ICONHAND );
-       
-       //}
-       // Returning EXCEPTION_EXECUTE_HANDLER means that the code in 
-       // the __execept block will be executed. Normally this will end up in a
-       // Terminate process.
-
-       return EXCEPTION_EXECUTE_HANDLER;
-       
+/*
+ * @unimplemented
+ */
+LONG STDCALL
+UnhandledExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo)
+{
+   DWORD RetValue;
+   HANDLE DebugPort = NULL;
+   NTSTATUS ErrCode;
+   static int RescursionTrap = 3;
+
+#if 0
+   if (ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION &&
+       ExceptionInfo->ExceptionRecord->ExceptionInformation[0])
+   {
+      RetValue = _BasepCheckForReadOnlyResource(
+         ExceptionInfo->ExceptionRecord->ExceptionInformation[1]);
+      if (RetValue == EXCEPTION_CONTINUE_EXECUTION)
+         return EXCEPTION_CONTINUE_EXECUTION;
+   }
+#endif
+
+   if (--RescursionTrap > 0)
+   {
+      /* Is there a debugger running ? */
+      ErrCode = NtQueryInformationProcess(NtCurrentProcess(), ProcessDebugPort,
+                                          &DebugPort, sizeof(HANDLE), NULL);
+      if (!NT_SUCCESS(ErrCode) && ErrCode != STATUS_NOT_IMPLEMENTED)
+      {
+         SetLastErrorByStatus(ErrCode);
+         return EXCEPTION_EXECUTE_HANDLER;
+      }
+
+      if (DebugPort)
+      {
+         /* Pass the exception to debugger. */
+         DPRINT("Passing exception to debugger\n");
+         return EXCEPTION_CONTINUE_SEARCH;
+      }
+
+      /* Run unhandled exception handler. */
+      if (GlobalTopLevelExceptionFilter != NULL)
+      {
+         RetValue = GlobalTopLevelExceptionFilter(ExceptionInfo);
+         if (RetValue == EXCEPTION_EXECUTE_HANDLER)
+            return EXCEPTION_EXECUTE_HANDLER;
+         if (RetValue == EXCEPTION_CONTINUE_EXECUTION) 
+            return EXCEPTION_CONTINUE_EXECUTION;
+      }
+   }
+
+   if (RescursionTrap >= 0 && (GetErrorMode() & SEM_NOGPFAULTERRORBOX) == 0)
+   {
+#ifdef _X86_
+      PULONG Frame;
+      CHAR szMod[128] = "";
+#endif
+
+      /* Print a stack trace. */
+      DPRINT1("Unhandled exception\n");
+      DPRINT1("Address:\n");
+      DPRINT1("   %8x   %s\n",
+         ExceptionInfo->ExceptionRecord->ExceptionAddress,
+         _module_name_from_addr(ExceptionInfo->ExceptionRecord->ExceptionAddress, szMod, sizeof(szMod)));
+      _dump_context ( ExceptionInfo->ContextRecord );
+#ifdef _X86_
+      DPRINT1("Frames:\n");
+      Frame = (PULONG)ExceptionInfo->ContextRecord->Ebp;
+      while (Frame[1] != 0 && Frame[1] != 0xdeadbeef)
+      {
+         if (IsBadReadPtr((PVOID)Frame[1], 4)) {
+           DPRINT1("   %8x   %s\n", Frame[1], "<invalid address>");
+         } else {
+           _module_name_from_addr((const void*)Frame[1], szMod, sizeof(szMod));
+           DPRINT1("   %8x   %s\n", Frame[1], szMod);
+         }
+         if (IsBadReadPtr((PVOID)Frame[0], sizeof(*Frame) * 2)) {
+           break;
+         }
+         Frame = (PULONG)Frame[0];
+      }
+#endif
+   }
+
+   /*
+    * Returning EXCEPTION_EXECUTE_HANDLER means that the code in 
+    * the __except block will be executed. Normally this will end up in a
+    * Terminate process.
+    */
+
+   return EXCEPTION_EXECUTE_HANDLER;   
 }
 
+
+/*
+ * @implemented
+ */
 VOID
 STDCALL
 RaiseException (
@@ -128,10 +211,9 @@ RaiseException (
        }
        /*
         * If the exception has no argument,
-        * or it is a non-continuable exception,
         * ignore nNumberOfArguments and lpArguments.
         */
-       if ((NULL == lpArguments) || ExceptionRecord.ExceptionFlags)
+       if (NULL == lpArguments)
        {
                ExceptionRecord.NumberParameters = 0;
        }