[KD64]
[reactos.git] / reactos / ntoskrnl / kd64 / kdbreak.c
index 4b9b9af..8cf6253 100644 (file)
-/*\r
- * PROJECT:         ReactOS Kernel\r
- * LICENSE:         GPL - See COPYING in the top level directory\r
- * FILE:            ntoskrnl/kd64/kdbreak.c\r
- * PURPOSE:         KD64 Breakpoint Support\r
- * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)\r
- */\r
-\r
-/* INCLUDES ******************************************************************/\r
-\r
-#include <ntoskrnl.h>\r
-#define NDEBUG\r
-#include <debug.h>\r
-\r
-/* FUNCTIONS *****************************************************************/\r
-\r
-BOOLEAN\r
-NTAPI\r
-KdpLowWriteContent(IN ULONG BpIndex)\r
-{\r
-    /* Make sure that the breakpoint is actually active */\r
-    if (KdpBreakpointTable[BpIndex].Flags & KdpBreakpointPending)\r
-    {\r
-        /* So we have a valid breakpoint, but it hasn't been used yet... */\r
-        KdpBreakpointTable[BpIndex].Flags &= ~KdpBreakpointPending;\r
-        return TRUE;\r
-    }\r
-\r
-    /* Is the original instruction an INT3 anyway? */\r
-    if (KdpBreakpointTable[BpIndex].Content == KdpBreakpointInstruction)\r
-    {\r
-        /* Then leave it that way... */\r
-        return TRUE;\r
-    }\r
-\r
-    /* We have an active breakpoint with an instruction to bring back. Do it. */\r
-    RtlCopyMemory(KdpBreakpointTable[BpIndex].Address,\r
-                  &KdpBreakpointTable[BpIndex].Content,\r
-                  sizeof(UCHAR));\r
-\r
-    /* Everything went fine, return */\r
-    return TRUE;\r
-}\r
-\r
-BOOLEAN\r
-NTAPI\r
-KdpLowRestoreBreakpoint(IN ULONG BpIndex)\r
-{\r
-    /* Were we not able to remove it earlier? */\r
-    if (KdpBreakpointTable[BpIndex].Flags & KdpBreakpointExpired)\r
-    {\r
-        /* Well then, we'll just re-use it and return success! */\r
-        KdpBreakpointTable[BpIndex].Flags &= ~KdpBreakpointExpired;\r
-        return TRUE;\r
-    }\r
-\r
-    /* Are we merely writing an INT3 on top of another INT3? */\r
-    if (KdpBreakpointTable[BpIndex].Content == KdpBreakpointInstruction)\r
-    {\r
-        /* Nothing to do then... */\r
-        return TRUE;\r
-    }\r
-\r
-    /* Ok, we actually have to overwrite the instruction now */\r
-    RtlCopyMemory(KdpBreakpointTable[BpIndex].Address,\r
-                  &KdpBreakpointInstruction,\r
-                  sizeof(UCHAR));\r
-\r
-    /* Clear any possible previous pending flag and return success */\r
-    KdpBreakpointTable[BpIndex].Flags &= ~KdpBreakpointPending;\r
-    return TRUE;\r
-}\r
-\r
-BOOLEAN\r
-NTAPI\r
-KdpDeleteBreakpoint(IN ULONG BpEntry)\r
-{\r
-    ULONG BpIndex = BpEntry - 1;\r
-\r
-    /* Check for invalid breakpoint entry */\r
-    if (!(BpEntry) || (BpEntry > 20)) return FALSE;\r
-\r
-    /* If the specified breakpoint table entry is not valid, then return FALSE. */\r
-    if (!KdpBreakpointTable[BpIndex].Flags) return FALSE;\r
-\r
-    /* Check if the breakpoint is suspended */\r
-    if (KdpBreakpointTable[BpIndex].Flags & KdpBreakpointSuspended)\r
-    {\r
-        /* Check if breakpoint is not ...? */\r
-        if (!(KdpBreakpointTable[BpIndex].Flags & KdpBreakpointExpired))\r
-        {\r
-            /* Invalidate it and return success */\r
-            KdpBreakpointTable[BpIndex].Flags = 0;\r
-            return TRUE;\r
-        }\r
-    }\r
-\r
-    /* Restore original data, then invalidate it and return success */\r
-    if (KdpLowWriteContent(BpIndex)) KdpBreakpointTable[BpIndex].Flags = 0;\r
-    return TRUE;\r
-}\r
-\r
-BOOLEAN\r
-NTAPI\r
-KdpDeleteBreakpointRange(IN PVOID Base,\r
-                         IN PVOID Limit)\r
-{\r
-    ULONG BpIndex;\r
-    BOOLEAN Return = FALSE;\r
-\r
-    /* Loop the breakpoint table */\r
-    for (BpIndex = 0; BpIndex < 20; BpIndex++)\r
-    {\r
-        /* Make sure that the breakpoint is active and matches the range. */\r
-        if ((KdpBreakpointTable[BpIndex].Flags & KdpBreakpointActive) &&\r
-            ((KdpBreakpointTable[BpIndex].Address >= Base) &&\r
-             (KdpBreakpointTable[BpIndex].Address <= Limit)))\r
-        {\r
-            /* Delete it */\r
-            Return = Return || KdpDeleteBreakpoint(BpIndex + 1);\r
-        }\r
-    }\r
-\r
-    /* Return to caller */\r
-    return Return;\r
-}\r
-\r
-VOID\r
-NTAPI\r
-KdpRestoreAllBreakpoints(VOID)\r
-{\r
-    ULONG BpIndex;\r
-\r
-    /* No more suspended Breakpoints */\r
-    BreakpointsSuspended = FALSE;\r
-\r
-    /* Loop the breakpoints */\r
-    for (BpIndex = 0; BpIndex < 20; BpIndex++ )\r
-    {\r
-        /* Check if they are valid, suspended breakpoints */\r
-        if ((KdpBreakpointTable[BpIndex].Flags & KdpBreakpointActive) &&\r
-            (KdpBreakpointTable[BpIndex].Flags & KdpBreakpointSuspended))\r
-        {\r
-            /* Unsuspend them */\r
-            KdpBreakpointTable[BpIndex].Flags &= ~KdpBreakpointSuspended;\r
-            KdpLowRestoreBreakpoint(BpIndex);\r
-        }\r
-    }\r
-}\r
+/*
+ * PROJECT:         ReactOS Kernel
+ * LICENSE:         GPL - See COPYING in the top level directory
+ * FILE:            ntoskrnl/kd64/kdbreak.c
+ * PURPOSE:         KD64 Breakpoint Support
+ * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <ntoskrnl.h>
+#define NDEBUG
+#include <debug.h>
+
+/* FUNCTIONS *****************************************************************/
+
+ULONG
+NTAPI
+KdpAddBreakpoint(IN PVOID Address)
+{
+    KD_BREAKPOINT_TYPE Content;
+    ULONG i;
+
+    /* Loop current breakpoints */
+    for (i = 0; i < KD_BREAKPOINT_MAX; i++)
+    {
+        /* Check if the breakpoint is valid */
+        if ((KdpBreakpointTable[i].Flags & KdpBreakpointActive) &&
+            (KdpBreakpointTable[i].Address == Address))
+        {
+            /* Check if it's pending */
+            if ((KdpBreakpointTable[i].Flags & KdpBreakpointPending))
+            {
+                /* It's not pending anymore now */
+                KdpBreakpointTable[i].Flags &= ~KdpBreakpointPending;
+                return i + 1;
+            }
+            else
+            {
+                /* Fail */
+                return 0;
+            }
+        }
+    }
+
+    /* Find a free entry */
+    for (i = 0; i < KD_BREAKPOINT_MAX; i++) if (!(KdpBreakpointTable[i].Flags)) break;
+
+    /* Fail if no free entry was found */
+    if (i == KD_BREAKPOINT_MAX) return 0;
+
+    /* Save the old instruction */
+    RtlCopyMemory(&Content, Address, KD_BREAKPOINT_SIZE);
+
+    /* Write the entry */
+    KdpBreakpointTable[i].Address = Address;
+    KdpBreakpointTable[i].Content = Content;
+    KdpBreakpointTable[i].Flags = KdpBreakpointActive;
+
+    /* Write the breakpoint and return the handle */
+    RtlCopyMemory(Address, &KdpBreakpointInstruction, KD_BREAKPOINT_SIZE);
+    return i + 1;
+}
+
+BOOLEAN
+NTAPI
+KdpLowWriteContent(IN ULONG BpIndex)
+{
+    /* Make sure that the breakpoint is actually active */
+    if (KdpBreakpointTable[BpIndex].Flags & KdpBreakpointPending)
+    {
+        /* So we have a valid breakpoint, but it hasn't been used yet... */
+        KdpBreakpointTable[BpIndex].Flags &= ~KdpBreakpointPending;
+        return TRUE;
+    }
+
+    /* Is the original instruction a breakpoint anyway? */
+    if (KdpBreakpointTable[BpIndex].Content == KdpBreakpointInstruction)
+    {
+        /* Then leave it that way... */
+        return TRUE;
+    }
+
+    /* We have an active breakpoint with an instruction to bring back. Do it. */
+    RtlCopyMemory(KdpBreakpointTable[BpIndex].Address,
+                  &KdpBreakpointTable[BpIndex].Content,
+                  KD_BREAKPOINT_SIZE);
+
+    /* Everything went fine, return */
+    return TRUE;
+}
+
+BOOLEAN
+NTAPI
+KdpLowRestoreBreakpoint(IN ULONG BpIndex)
+{
+    /* Were we not able to remove it earlier? */
+    if (KdpBreakpointTable[BpIndex].Flags & KdpBreakpointExpired)
+    {
+        /* Well then, we'll just re-use it and return success! */
+        KdpBreakpointTable[BpIndex].Flags &= ~KdpBreakpointExpired;
+        return TRUE;
+    }
+
+    /* Are we merely writing a breakpoint on top of another breakpoint? */
+    if (KdpBreakpointTable[BpIndex].Content == KdpBreakpointInstruction)
+    {
+        /* Nothing to do then... */
+        return TRUE;
+    }
+
+    /* Ok, we actually have to overwrite the instruction now */
+    RtlCopyMemory(KdpBreakpointTable[BpIndex].Address,
+                  &KdpBreakpointInstruction,
+                  KD_BREAKPOINT_SIZE);
+
+    /* Clear any possible previous pending flag and return success */
+    KdpBreakpointTable[BpIndex].Flags &= ~KdpBreakpointPending;
+    return TRUE;
+}
+
+BOOLEAN
+NTAPI
+KdpDeleteBreakpoint(IN ULONG BpEntry)
+{
+    ULONG BpIndex = BpEntry - 1;
+
+    /* Check for invalid breakpoint entry */
+    if (!(BpEntry) || (BpEntry > KD_BREAKPOINT_MAX)) return FALSE;
+
+    /* If the specified breakpoint table entry is not valid, then return FALSE. */
+    if (!KdpBreakpointTable[BpIndex].Flags) return FALSE;
+
+    /* Check if the breakpoint is suspended */
+    if (KdpBreakpointTable[BpIndex].Flags & KdpBreakpointSuspended)
+    {
+        /* Check if breakpoint is not ...? */
+        if (!(KdpBreakpointTable[BpIndex].Flags & KdpBreakpointExpired))
+        {
+            /* Invalidate it and return success */
+            KdpBreakpointTable[BpIndex].Flags = 0;
+            return TRUE;
+        }
+    }
+
+    /* Restore original data, then invalidate it and return success */
+    if (KdpLowWriteContent(BpIndex)) KdpBreakpointTable[BpIndex].Flags = 0;
+    return TRUE;
+}
+
+BOOLEAN
+NTAPI
+KdpDeleteBreakpointRange(IN PVOID Base,
+                         IN PVOID Limit)
+{
+    ULONG BpIndex;
+    BOOLEAN Return = FALSE;
+
+    /* Loop the breakpoint table */
+    for (BpIndex = 0; BpIndex < KD_BREAKPOINT_MAX; BpIndex++)
+    {
+        /* Make sure that the breakpoint is active and matches the range. */
+        if ((KdpBreakpointTable[BpIndex].Flags & KdpBreakpointActive) &&
+            ((KdpBreakpointTable[BpIndex].Address >= Base) &&
+             (KdpBreakpointTable[BpIndex].Address <= Limit)))
+        {
+            /* Delete it */
+            Return = Return || KdpDeleteBreakpoint(BpIndex + 1);
+        }
+    }
+
+    /* Return to caller */
+    return Return;
+}
+
+VOID
+NTAPI
+KdpRestoreAllBreakpoints(VOID)
+{
+    ULONG BpIndex;
+
+    /* No more suspended Breakpoints */
+    BreakpointsSuspended = FALSE;
+
+    /* Loop the breakpoints */
+    for (BpIndex = 0; BpIndex < KD_BREAKPOINT_MAX; BpIndex++ )
+    {
+        /* Check if they are valid, suspended breakpoints */
+        if ((KdpBreakpointTable[BpIndex].Flags & KdpBreakpointActive) &&
+            (KdpBreakpointTable[BpIndex].Flags & KdpBreakpointSuspended))
+        {
+            /* Unsuspend them */
+            KdpBreakpointTable[BpIndex].Flags &= ~KdpBreakpointSuspended;
+            KdpLowRestoreBreakpoint(BpIndex);
+        }
+    }
+}