Merge trunk head (r43756)
[reactos.git] / reactos / ntoskrnl / ke / bug.c
index 0bf887a..f9cc43e 100644 (file)
@@ -10,7 +10,7 @@
 
 #include <ntoskrnl.h>
 #define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
 
 #if defined (ALLOC_PRAGMA)
 #pragma alloc_text(INIT, KiInitializeBugCheck)
@@ -37,13 +37,13 @@ UNICODE_STRING KeRosVideoBiosDate, KeRosVideoBiosVersion;
 
 PVOID
 NTAPI
-KiPcToFileHeader(IN PVOID Eip,
+KiPcToFileHeader(IN PVOID Pc,
                  OUT PLDR_DATA_TABLE_ENTRY *LdrEntry,
                  IN BOOLEAN DriversOnly,
                  OUT PBOOLEAN InKernel)
 {
     ULONG i = 0;
-    PVOID ImageBase, EipBase = NULL;
+    PVOID ImageBase, PcBase = NULL;
     PLDR_DATA_TABLE_ENTRY Entry;
     PLIST_ENTRY ListHead, NextEntry;
 
@@ -82,12 +82,12 @@ KiPcToFileHeader(IN PVOID Eip,
             ImageBase = Entry->DllBase;
 
             /* Check if this is the right one */
-            if (((ULONG_PTR)Eip >= (ULONG_PTR)Entry->DllBase) &&
-                ((ULONG_PTR)Eip < ((ULONG_PTR)Entry->DllBase + Entry->SizeOfImage)))
+            if (((ULONG_PTR)Pc >= (ULONG_PTR)Entry->DllBase) &&
+                ((ULONG_PTR)Pc < ((ULONG_PTR)Entry->DllBase + Entry->SizeOfImage)))
             {
                 /* Return this entry */
                 *LdrEntry = Entry;
-                EipBase = ImageBase;
+                PcBase = ImageBase;
 
                 /* Check if this was a kernel or HAL entry */
                 if (i <= 2) *InKernel = TRUE;
@@ -97,7 +97,7 @@ KiPcToFileHeader(IN PVOID Eip,
     }
 
     /* Return the base address */
-    return EipBase;
+    return PcBase;
 }
 
 BOOLEAN
@@ -136,65 +136,200 @@ KiRosPrintAddress(PVOID address)
     return(FALSE);
 }
 
-VOID
+PVOID
 NTAPI
-KeRosDumpStackFrames(IN PULONG Frame OPTIONAL,
-                     IN ULONG FrameCount OPTIONAL)
+KiRosPcToUserFileHeader(IN PVOID Pc,
+                        OUT PLDR_DATA_TABLE_ENTRY *LdrEntry)
 {
-    ULONG Frames[32];
-    ULONG i, Addr;
-    BOOLEAN InSystem;
-    PLDR_DATA_TABLE_ENTRY LdrEntry;
+    PVOID ImageBase, PcBase = NULL;
+    PLDR_DATA_TABLE_ENTRY Entry;
+    PLIST_ENTRY ListHead, NextEntry;
 
-    /* If the caller didn't ask, assume 32 frames */
-    if (!FrameCount || FrameCount > 32) FrameCount = 32;
+    /*
+     * We know this is valid because we should only be called after a
+     * succesfull address from RtlWalkFrameChain for UserMode, which
+     * validates everything for us.
+     */
+    ListHead = &KeGetCurrentThread()->
+               Teb->ProcessEnvironmentBlock->Ldr->InLoadOrderModuleList;
+
+    /* Set list pointers and make sure it's valid */
+    NextEntry = ListHead->Flink;
+    if (NextEntry)
+    {
+        /* Start loop */
+        while (NextEntry != ListHead)
+        {
+            /* Get the loader entry */
+            Entry = CONTAINING_RECORD(NextEntry,
+                                      LDR_DATA_TABLE_ENTRY,
+                                      InLoadOrderLinks);
+
+            /* Move to the next entry */
+            NextEntry = NextEntry->Flink;
+            ImageBase = Entry->DllBase;
+
+            /* Check if this is the right one */
+            if (((ULONG_PTR)Pc >= (ULONG_PTR)Entry->DllBase) &&
+                ((ULONG_PTR)Pc < ((ULONG_PTR)Entry->DllBase + Entry->SizeOfImage)))
+            {
+                /* Return this entry */
+                *LdrEntry = Entry;
+                PcBase = ImageBase;
+                break;
+            }
+        }
+    }
+
+    /* Return the base address */
+    return PcBase;
+}
+
+USHORT
+NTAPI
+KeRosCaptureUserStackBackTrace(IN ULONG FramesToSkip,
+                               IN ULONG FramesToCapture,
+                               OUT PVOID *BackTrace,
+                               OUT PULONG BackTraceHash OPTIONAL)
+{
+    PVOID Frames[2 * 64];
+    ULONG FrameCount;
+    ULONG Hash = 0, i;
+
+    /* Skip a frame for the caller */
+    FramesToSkip++;
+
+    /* Don't go past the limit */
+    if ((FramesToCapture + FramesToSkip) >= 128) return 0;
+
+    /* Do the back trace */
+    FrameCount = RtlWalkFrameChain(Frames, FramesToCapture + FramesToSkip, 1);
+
+    /* Make sure we're not skipping all of them */
+    if (FrameCount <= FramesToSkip) return 0;
+
+    /* Loop all the frames */
+    for (i = 0; i < FramesToCapture; i++)
+    {
+        /* Don't go past the limit */
+        if ((FramesToSkip + i) >= FrameCount) break;
+
+        /* Save this entry and hash it */
+        BackTrace[i] = Frames[FramesToSkip + i];
+        Hash += PtrToUlong(BackTrace[i]);
+    }
+
+    /* Write the hash */
+    if (BackTraceHash) *BackTraceHash = Hash;
 
-    /* Get the current frames */
-    FrameCount = RtlCaptureStackBackTrace(2, FrameCount, (PVOID*)Frames, NULL);
+    /* Clear the other entries and return count */
+    RtlFillMemoryUlong(Frames, 128, 0);
+    return (USHORT)i;
+}
 
-    /* Now loop them (skip the two. One for the dumper, one for the caller) */
+VOID
+FASTCALL
+KeRosDumpStackFrameArray(IN PULONG_PTR Frames,
+                         IN ULONG FrameCount)
+{
+    ULONG i;
+    ULONG_PTR Addr;
+    BOOLEAN InSystem;
+    PVOID p;
+
+    /* GCC complaints that it may be used uninitialized */
+    PLDR_DATA_TABLE_ENTRY LdrEntry = NULL;
+
+    /* Loop them */
     for (i = 0; i < FrameCount; i++)
     {
         /* Get the EIP */
         Addr = Frames[i];
+        if (!Addr)
+        {
+               break;
+        }
 
-        /* If we had a custom frame, make sure we've reached it first */
-        if ((Frame) && (Frame[1] == Addr))
+        /* Get the base for this file */
+        if (Addr > (ULONG_PTR)MmHighestUserAddress)
+        {
+            /* We are in kernel */
+            p = KiPcToFileHeader((PVOID)Addr, &LdrEntry, FALSE, &InSystem);
+        }
+        else
         {
-            Frame = NULL;
+            /* We are in user land */
+            p = KiRosPcToUserFileHeader((PVOID)Addr, &LdrEntry);
         }
-        else if (Frame)
+        if (p)
         {
-            /* Skip this entry */
-            continue;
+#ifdef KDBG
+            if (!KdbSymPrintAddress((PVOID)Addr))
+#endif
+            {
+                /* Print out the module name */
+                Addr -= (ULONG_PTR)LdrEntry->DllBase;
+                DbgPrint("<%wZ: %p>", &LdrEntry->FullDllName, (PVOID)Addr);
+            }
         }
-
-        /* Get the base for this file */
-        if (KiPcToFileHeader((PVOID)Addr, &LdrEntry, FALSE, &InSystem))
+        else
         {
-            /* Print out the module name */
-            Addr -= (ULONG_PTR)LdrEntry->DllBase;
-            DbgPrint("<%wZ: %x>", &LdrEntry->FullDllName, Addr);
+            /* Print only the address */
+            DbgPrint("<%p>", (PVOID)Addr);
         }
 
         /* Go to the next frame */
         DbgPrint("\n");
     }
+}
+
+VOID
+NTAPI
+KeRosDumpStackFrames(IN PULONG_PTR Frame OPTIONAL,
+                     IN ULONG FrameCount OPTIONAL)
+{
+    ULONG_PTR Frames[32];
+    ULONG RealFrameCount;
+
+    /* If the caller didn't ask, assume 32 frames */
+    if (!FrameCount || FrameCount > 32) FrameCount = 32;
+
+    if (Frame)
+    {
+        /* Dump them */
+        KeRosDumpStackFrameArray(Frame, FrameCount);
+    }
+    else
+    {
+        /* Get the current frames (skip the two. One for the dumper, one for the caller) */
+        RealFrameCount = RtlCaptureStackBackTrace(2, FrameCount, (PVOID*)Frames, NULL);
 
-    /* Finish the output */
-    DbgPrint("\n");
+        /* Dump them */
+        KeRosDumpStackFrameArray(Frames, RealFrameCount);
+
+        /* Count left for user mode? */
+        if (FrameCount - RealFrameCount > 0)
+        {
+            /* Get the current frames */
+            RealFrameCount = KeRosCaptureUserStackBackTrace(-1, FrameCount - RealFrameCount, (PVOID*)Frames, NULL);
+
+            /* Dump them */
+            KeRosDumpStackFrameArray(Frames, RealFrameCount);
+        }
+    }
 }
 
+
 VOID
 NTAPI
 KeRosDumpTriageForBugZillaReport(VOID)
 {
+#if 0
     extern BOOLEAN KiFastSystemCallDisable, KiSMTProcessorsPresent;
     extern ULONG KeI386MachineType, MxcsrFeatureMask;
     extern BOOLEAN Ke386Pae, Ke386NoExecute;
 
     DbgPrint("ReactOS has crashed! Please go to http://www.reactos.org/bugzilla/enter_bug.cgi to file a bug!\n");
-#ifdef __i386__
     DbgPrint("\nHardware Information\n");
     DbgPrint("Processor Architecture: %d\n"
              "Feature Bits: %d\n"
@@ -416,9 +551,25 @@ VOID
 NTAPI
 KiBugCheckDebugBreak(IN ULONG StatusCode)
 {
-    /* If KDBG isn't connected, freeze the CPU, otherwise, break */
-    if (KdDebuggerNotPresent) for (;;) Ke386HaltProcessor();
-    DbgBreakPointWithStatus(StatusCode);
+    /*
+     * Wrap this in SEH so we don't crash if
+     * there is no debugger or if it disconnected
+     */
+DoBreak:
+    _SEH2_TRY
+    {
+        /* Breakpoint */
+        DbgBreakPointWithStatus(StatusCode);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        /* No debugger, halt the CPU */
+        HalHaltSystem();
+    }
+    _SEH2_END;
+
+    /* Break again if this wasn't first try */
+    if (StatusCode != DBG_STATUS_BUGCHECK_FIRST) goto DoBreak;
 }
 
 PCHAR
@@ -472,13 +623,9 @@ KiDumpParameterImages(IN PCHAR Message,
                                      &InSystem);
         if (!ImageBase)
         {
-            /* Driver wasn't found, check for unloaded driver */
-            DriverName = NULL; // FIXME: ROS can't
-            if (!DriverName) continue;
-
-            /* Convert the driver name */
-            ImageBase = (PVOID)Parameters[i];
-            ConversionRoutine(DriverName, AnsiName, sizeof(AnsiName));
+            /* FIXME: Add code to check for unloaded drivers */
+            DPRINT1("Potentially unloaded driver!\n");
+            continue;
         }
         else
         {
@@ -593,8 +740,8 @@ KiDisplayBlueScreen(IN ULONG MessageId,
 
     /* Show the technical Data */
     sprintf(AnsiName,
-            "\r\n\r\n*** STOP: 0x%08lX (0x%p,0x%p,0x%p,0x%p)\r\n\r\n",
-            KiBugCheckData[0],
+            "\r\n\r\n*** STOP: 0x%p (0x%p,0x%p,0x%p,0x%p)\r\n\r\n",
+            (PVOID)KiBugCheckData[0],
             (PVOID)KiBugCheckData[1],
             (PVOID)KiBugCheckData[2],
             (PVOID)KiBugCheckData[3],
@@ -632,10 +779,11 @@ KeBugCheckWithTf(IN ULONG BugCheckCode,
     CHAR AnsiName[128];
     BOOLEAN IsSystem, IsHardError = FALSE, Reboot = FALSE;
     PCHAR HardErrCaption = NULL, HardErrMessage = NULL;
-    PVOID Eip = NULL, Memory;
+    PVOID Pc = NULL, Memory;
     PVOID DriverBase;
     PLDR_DATA_TABLE_ENTRY LdrEntry;
     PULONG_PTR HardErrorParameters;
+    KIRQL OldIrql;
 #ifdef CONFIG_SMP
     LONG i = 0;
 #endif
@@ -741,12 +889,12 @@ KeBugCheckWithTf(IN ULONG BugCheckCode,
                 if (BugCheckParameter3) TrapFrame = (PVOID)BugCheckParameter3;
             }
 
-            /* Check if we got one now and if we need to get EIP */
+            /* Check if we got one now and if we need to get the Program Counter */
             if ((TrapFrame) &&
                 (BugCheckCode != KERNEL_MODE_EXCEPTION_NOT_HANDLED))
             {
-                /* Get EIP */
-                Eip = (PVOID)TrapFrame->Eip;
+                /* Get the Program Counter */
+                Pc = (PVOID)KeGetTrapFramePc(TrapFrame);
             }
             break;
 
@@ -760,11 +908,14 @@ KeBugCheckWithTf(IN ULONG BugCheckCode,
              * and provide a more detailed analysis. For now, we don't.
              */
 
-            /* Eip is in parameter 4 */
-            Eip = (PVOID)BugCheckParameter4;
+            /* Program Counter is in parameter 4 */
+            Pc = (PVOID)BugCheckParameter4;
 
             /* Get the driver base */
-            DriverBase = KiPcToFileHeader(Eip, &LdrEntry, FALSE, &IsSystem);
+            DriverBase = KiPcToFileHeader(Pc,
+                                          &LdrEntry,
+                                          FALSE,
+                                          &IsSystem);
             if (IsSystem)
             {
                 /*
@@ -804,8 +955,8 @@ KeBugCheckWithTf(IN ULONG BugCheckCode,
                 KiBugCheckData[0] = DRIVER_IRQL_NOT_LESS_OR_EQUAL;
             }
 
-            /* Clear EIP so we don't look it up later */
-            Eip = NULL;
+            /* Clear Pc so we don't look it up later */
+            Pc = NULL;
             break;
 
         /* Hard error */
@@ -841,12 +992,12 @@ KeBugCheckWithTf(IN ULONG BugCheckCode,
             /* Check if we have a frame now */
             if (TrapFrame)
             {
-                /* Get EIP */
-                Eip = (PVOID)TrapFrame->Eip;
-                KiBugCheckData[3] = (ULONG)Eip;
+                /* Get the Program Counter */
+                Pc = (PVOID)KeGetTrapFramePc(TrapFrame);
+                KiBugCheckData[3] = (ULONG_PTR)Pc;
 
                 /* Find out if was in the kernel or drivers */
-                DriverBase = KiPcToFileHeader(Eip,
+                DriverBase = KiPcToFileHeader(Pc,
                                               &LdrEntry,
                                               FALSE,
                                               &IsSystem);
@@ -876,8 +1027,8 @@ KeBugCheckWithTf(IN ULONG BugCheckCode,
         /* Check if the driver forgot to unlock pages */
         case DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS:
 
-            /* EIP is in parameter 1 */
-            Eip = (PVOID)BugCheckParameter1;
+            /* Program Counter is in parameter 1 */
+            Pc = (PVOID)BugCheckParameter1;
             break;
 
         /* Check if the driver consumed too many PTEs */
@@ -908,12 +1059,12 @@ KeBugCheckWithTf(IN ULONG BugCheckCode,
     }
     else
     {
-        /* Do we have an EIP? */
-        if (Eip)
+        /* Do we have a Program Counter? */
+        if (Pc)
         {
             /* Dump image name */
             KiDumpParameterImages(AnsiName,
-                                  (PULONG_PTR)&Eip,
+                                  (PULONG_PTR)&Pc,
                                   1,
                                   KeBugCheckUnicodeToAnsi);
         }
@@ -921,7 +1072,7 @@ KeBugCheckWithTf(IN ULONG BugCheckCode,
 
     /* Check if we need to save the context for KD */
 #ifdef _WINKD_
-    if (!KdPitchDebugger) KdDebuggerDataBlock.SavedContext = (ULONG)&Context;
+    if (!KdPitchDebugger) KdDebuggerDataBlock.SavedContext = (ULONG_PTR)&Context;
 #endif
 
     /* Check if a debugger is connected */
@@ -965,15 +1116,15 @@ KeBugCheckWithTf(IN ULONG BugCheckCode,
              * We'll manually dump the stack for the user.
              */
             KeRosDumpStackFrames(NULL, 0);
-            
+
             /* ROS HACK 2: Generate something useful for Bugzilla */
             KeRosDumpTriageForBugZillaReport();
         }
     }
 
-    /* Raise IRQL to HIGH_LEVEL */    
+    /* Raise IRQL to HIGH_LEVEL */
     _disable();
-    KfRaiseIrql(HIGH_LEVEL);
+    KeRaiseIrql(HIGH_LEVEL, &OldIrql);
 
     /* Avoid recursion */
     if (!InterlockedDecrement((PLONG)&KeBugCheckCount))
@@ -988,20 +1139,18 @@ KeBugCheckWithTf(IN ULONG BugCheckCode,
             if (i != (LONG)KeGetCurrentProcessorNumber())
             {
                 /* Send the IPI and give them one second to catch up */
-                KiIpiSendRequest(1 << i, IPI_FREEZE);
+                KiIpiSend(1 << i, IPI_FREEZE);
                 KeStallExecutionProcessor(1000000);
             }
         }
 #endif
 
         /* Display the BSOD */
-        KfLowerIrql(APC_LEVEL); // This is a nastier hack than any ever before
         KiDisplayBlueScreen(MessageId,
                             IsHardError,
                             HardErrCaption,
                             HardErrMessage,
                             AnsiName);
-        KfRaiseIrql(HIGH_LEVEL);
 
         /* Check if the debugger is disabled but we can enable it */
         if (!(KdDebuggerEnabled) && !(KdPitchDebugger))
@@ -1022,13 +1171,7 @@ KeBugCheckWithTf(IN ULONG BugCheckCode,
 
         /* FIXME: Support Triage Dump */
 
-        /* Write the crash dump */
-        MmDumpToPagingFile(KiBugCheckData[4],
-                           KiBugCheckData[0],
-                           KiBugCheckData[1],
-                           KiBugCheckData[2],
-                           KiBugCheckData[3],
-                           TrapFrame);
+        /* FIXME: Write the crash dump */
     }
     else
     {
@@ -1041,8 +1184,8 @@ KeBugCheckWithTf(IN ULONG BugCheckCode,
         }
         else if (KeBugCheckOwnerRecursionCount > 2)
         {
-            /* Halt the CPU */
-            for (;;) Ke386HaltProcessor();
+            /* Halt execution */
+            while (TRUE);
         }
     }
 
@@ -1055,16 +1198,34 @@ KeBugCheckWithTf(IN ULONG BugCheckCode,
     if (Reboot)
     {
         /* Unload symbols */
-        DbgUnLoadImageSymbols(NULL, NtCurrentProcess(), 0);
+        DbgUnLoadImageSymbols(NULL, (PVOID)MAXULONG_PTR, 0);
         HalReturnToFirmware(HalRebootRoutine);
     }
 
     /* Attempt to break in the debugger (otherwise halt CPU) */
     KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND);
+
+    /* Shouldn't get here */
+    while (TRUE);
 }
 
 /* PUBLIC FUNCTIONS **********************************************************/
 
+/*
+ * @unimplemented
+ */
+NTSTATUS
+NTAPI
+KeInitializeCrashDumpHeader(IN ULONG Type,
+                            IN ULONG Flags,
+                            OUT PVOID Buffer,
+                            IN ULONG BufferSize,
+                            OUT ULONG BufferNeeded OPTIONAL)
+{
+    UNIMPLEMENTED;
+    return STATUS_UNSUCCESSFUL;
+}
+
 /*
  * @implemented
  */
@@ -1120,6 +1281,17 @@ KeDeregisterBugCheckReasonCallback(
     return Status;
 }
 
+/*
+ * @unimplemented
+ */
+NTSTATUS
+NTAPI
+KeDeregisterNmiCallback(PVOID Handle)
+{
+    UNIMPLEMENTED;
+    return STATUS_UNSUCCESSFUL;
+}
+
 /*
  * @implemented
  */
@@ -1190,6 +1362,18 @@ KeRegisterBugCheckReasonCallback(
     return Status;
 }
 
+/*
+ * @unimplemented
+ */
+PVOID
+NTAPI
+KeRegisterNmiCallback(IN PNMI_CALLBACK CallbackRoutine,
+                      IN PVOID Context)
+{
+    UNIMPLEMENTED;
+    return NULL;
+}
+
 /*
  * @implemented
  */
@@ -1243,7 +1427,7 @@ KeEnterKernelDebugger(VOID)
         }
     }
 
-    /* Bugcheck */
+    /* Break in the debugger */
     KiBugCheckDebugBreak(DBG_STATUS_FATAL);
 }