- Sync up Mm interface with WinLdr branch (introduce the concept of a memory type...
[reactos.git] / reactos / ntoskrnl / kd64 / kdbreak.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/kd64/kdbreak.c
5 * PURPOSE: KD64 Breakpoint Support
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* FUNCTIONS *****************************************************************/
16
17 ULONG
18 NTAPI
19 KdpAddBreakpoint(IN PVOID Address)
20 {
21 UCHAR Content;
22 ULONG i;
23
24 /* Loop current breakpoints */
25 for (i = 0; i < 20; i++)
26 {
27 /* Check if the breakpoint is valid */
28 if ((KdpBreakpointTable[i].Flags & KdpBreakpointActive) &&
29 (KdpBreakpointTable[i].Address == Address))
30 {
31 /* Check if it's pending */
32 if ((KdpBreakpointTable[i].Flags & KdpBreakpointPending))
33 {
34 /* It's not pending anymore now */
35 KdpBreakpointTable[i].Flags &= ~KdpBreakpointPending;
36 return i + 1;
37 }
38 else
39 {
40 /* Fail */
41 return 0;
42 }
43 }
44 }
45
46 /* Find a free entry */
47 for (i = 0; i < 20; i++) if (!(KdpBreakpointTable[i].Flags)) break;
48
49 /* Fail if no free entry was found */
50 if (i == 20) return 0;
51
52 /* Save the old instruction */
53 RtlCopyMemory(&Content, Address, sizeof(UCHAR));
54
55 /* Write the entry */
56 KdpBreakpointTable[i].Address = Address;
57 KdpBreakpointTable[i].Content = Content;
58 KdpBreakpointTable[i].Flags = KdpBreakpointActive;
59
60 /* Write the INT3 and return the handle */
61 RtlCopyMemory(Address, &KdpBreakpointInstruction, sizeof(UCHAR));
62 return i + 1;
63 }
64
65 BOOLEAN
66 NTAPI
67 KdpLowWriteContent(IN ULONG BpIndex)
68 {
69 /* Make sure that the breakpoint is actually active */
70 if (KdpBreakpointTable[BpIndex].Flags & KdpBreakpointPending)
71 {
72 /* So we have a valid breakpoint, but it hasn't been used yet... */
73 KdpBreakpointTable[BpIndex].Flags &= ~KdpBreakpointPending;
74 return TRUE;
75 }
76
77 /* Is the original instruction an INT3 anyway? */
78 if (KdpBreakpointTable[BpIndex].Content == KdpBreakpointInstruction)
79 {
80 /* Then leave it that way... */
81 return TRUE;
82 }
83
84 /* We have an active breakpoint with an instruction to bring back. Do it. */
85 RtlCopyMemory(KdpBreakpointTable[BpIndex].Address,
86 &KdpBreakpointTable[BpIndex].Content,
87 sizeof(UCHAR));
88
89 /* Everything went fine, return */
90 return TRUE;
91 }
92
93 BOOLEAN
94 NTAPI
95 KdpLowRestoreBreakpoint(IN ULONG BpIndex)
96 {
97 /* Were we not able to remove it earlier? */
98 if (KdpBreakpointTable[BpIndex].Flags & KdpBreakpointExpired)
99 {
100 /* Well then, we'll just re-use it and return success! */
101 KdpBreakpointTable[BpIndex].Flags &= ~KdpBreakpointExpired;
102 return TRUE;
103 }
104
105 /* Are we merely writing an INT3 on top of another INT3? */
106 if (KdpBreakpointTable[BpIndex].Content == KdpBreakpointInstruction)
107 {
108 /* Nothing to do then... */
109 return TRUE;
110 }
111
112 /* Ok, we actually have to overwrite the instruction now */
113 RtlCopyMemory(KdpBreakpointTable[BpIndex].Address,
114 &KdpBreakpointInstruction,
115 sizeof(UCHAR));
116
117 /* Clear any possible previous pending flag and return success */
118 KdpBreakpointTable[BpIndex].Flags &= ~KdpBreakpointPending;
119 return TRUE;
120 }
121
122 BOOLEAN
123 NTAPI
124 KdpDeleteBreakpoint(IN ULONG BpEntry)
125 {
126 ULONG BpIndex = BpEntry - 1;
127
128 /* Check for invalid breakpoint entry */
129 if (!(BpEntry) || (BpEntry > 20)) return FALSE;
130
131 /* If the specified breakpoint table entry is not valid, then return FALSE. */
132 if (!KdpBreakpointTable[BpIndex].Flags) return FALSE;
133
134 /* Check if the breakpoint is suspended */
135 if (KdpBreakpointTable[BpIndex].Flags & KdpBreakpointSuspended)
136 {
137 /* Check if breakpoint is not ...? */
138 if (!(KdpBreakpointTable[BpIndex].Flags & KdpBreakpointExpired))
139 {
140 /* Invalidate it and return success */
141 KdpBreakpointTable[BpIndex].Flags = 0;
142 return TRUE;
143 }
144 }
145
146 /* Restore original data, then invalidate it and return success */
147 if (KdpLowWriteContent(BpIndex)) KdpBreakpointTable[BpIndex].Flags = 0;
148 return TRUE;
149 }
150
151 BOOLEAN
152 NTAPI
153 KdpDeleteBreakpointRange(IN PVOID Base,
154 IN PVOID Limit)
155 {
156 ULONG BpIndex;
157 BOOLEAN Return = FALSE;
158
159 /* Loop the breakpoint table */
160 for (BpIndex = 0; BpIndex < 20; BpIndex++)
161 {
162 /* Make sure that the breakpoint is active and matches the range. */
163 if ((KdpBreakpointTable[BpIndex].Flags & KdpBreakpointActive) &&
164 ((KdpBreakpointTable[BpIndex].Address >= Base) &&
165 (KdpBreakpointTable[BpIndex].Address <= Limit)))
166 {
167 /* Delete it */
168 Return = Return || KdpDeleteBreakpoint(BpIndex + 1);
169 }
170 }
171
172 /* Return to caller */
173 return Return;
174 }
175
176 VOID
177 NTAPI
178 KdpRestoreAllBreakpoints(VOID)
179 {
180 ULONG BpIndex;
181
182 /* No more suspended Breakpoints */
183 BreakpointsSuspended = FALSE;
184
185 /* Loop the breakpoints */
186 for (BpIndex = 0; BpIndex < 20; BpIndex++ )
187 {
188 /* Check if they are valid, suspended breakpoints */
189 if ((KdpBreakpointTable[BpIndex].Flags & KdpBreakpointActive) &&
190 (KdpBreakpointTable[BpIndex].Flags & KdpBreakpointSuspended))
191 {
192 /* Unsuspend them */
193 KdpBreakpointTable[BpIndex].Flags &= ~KdpBreakpointSuspended;
194 KdpLowRestoreBreakpoint(BpIndex);
195 }
196 }
197 }