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 * Stefan Ginsberg (stefan.ginsberg@reactos.org)
10 /* INCLUDES ******************************************************************/
16 /* FUNCTIONS *****************************************************************/
20 KdpAddBreakpoint(IN PVOID Address
)
22 KD_BREAKPOINT_TYPE Content
;
26 /* Check whether we are not setting a breakpoint twice */
27 for (i
= 0; i
< KD_BREAKPOINT_MAX
; i
++)
29 /* Check if the breakpoint is valid */
30 if ((KdpBreakpointTable
[i
].Flags
& KD_BREAKPOINT_ACTIVE
) &&
31 (KdpBreakpointTable
[i
].Address
== Address
))
33 /* Were we not able to remove it earlier? */
34 if (KdpBreakpointTable
[i
].Flags
& KD_BREAKPOINT_EXPIRED
)
37 KdpBreakpointTable
[i
].Flags
&= ~KD_BREAKPOINT_EXPIRED
;
48 /* Find a free entry */
49 for (i
= 0; i
< KD_BREAKPOINT_MAX
; i
++)
51 if (KdpBreakpointTable
[i
].Flags
== 0)
55 /* Fail if no free entry was found */
56 if (i
== KD_BREAKPOINT_MAX
) return 0;
58 /* Save the breakpoint */
59 KdpBreakpointTable
[i
].Address
= Address
;
61 /* If we are setting the breakpoint in user space, save the active process context */
62 if (Address
< KD_HIGHEST_USER_BREAKPOINT_ADDRESS
)
63 KdpBreakpointTable
[i
].DirectoryTableBase
= KeGetCurrentThread()->ApcState
.Process
->DirectoryTableBase
[0];
65 /* Try to save the old instruction */
66 Status
= KdpCopyMemoryChunks((ULONG_PTR
)Address
,
72 if (NT_SUCCESS(Status
))
74 /* Memory accessible, set the breakpoint */
75 KdpBreakpointTable
[i
].Content
= Content
;
76 KdpBreakpointTable
[i
].Flags
= KD_BREAKPOINT_ACTIVE
;
78 /* Write the breakpoint */
79 Status
= KdpCopyMemoryChunks((ULONG_PTR
)Address
,
80 &KdpBreakpointInstruction
,
83 MMDBG_COPY_UNSAFE
| MMDBG_COPY_WRITE
,
85 if (!NT_SUCCESS(Status
))
87 /* This should never happen */
88 KdpDprintf("Unable to write breakpoint to address 0x%p\n", Address
);
93 /* Memory is inaccessible now, setting breakpoint is deferred */
94 KdpDprintf("Failed to set breakpoint at address 0x%p, adding deferred breakpoint.\n", Address
);
95 KdpBreakpointTable
[i
].Flags
= KD_BREAKPOINT_ACTIVE
| KD_BREAKPOINT_PENDING
;
96 KdpOweBreakpoint
= TRUE
;
99 /* Return the breakpoint handle */
105 KdSetOwedBreakpoints(VOID
)
108 KD_BREAKPOINT_TYPE Content
;
112 /* If we don't owe any breakpoints, just return */
113 if (!KdpOweBreakpoint
) return;
115 /* Enter the debugger */
116 Enable
= KdEnterDebugger(NULL
, NULL
);
119 * Suppose we succeed in setting all the breakpoints.
120 * If we fail to do so, the flag will be set again.
122 KdpOweBreakpoint
= FALSE
;
124 /* Loop through current breakpoints and try to set or delete the pending ones */
125 for (i
= 0; i
< KD_BREAKPOINT_MAX
; i
++)
127 if (KdpBreakpointTable
[i
].Flags
& (KD_BREAKPOINT_PENDING
| KD_BREAKPOINT_EXPIRED
))
130 * Set the breakpoint only if it is in kernel space, or if it is
131 * in user space and the active process context matches.
133 if (KdpBreakpointTable
[i
].Address
< KD_HIGHEST_USER_BREAKPOINT_ADDRESS
&&
134 KdpBreakpointTable
[i
].DirectoryTableBase
!= KeGetCurrentThread()->ApcState
.Process
->DirectoryTableBase
[0])
136 KdpOweBreakpoint
= TRUE
;
140 /* Try to save the old instruction */
141 Status
= KdpCopyMemoryChunks((ULONG_PTR
)KdpBreakpointTable
[i
].Address
,
147 if (!NT_SUCCESS(Status
))
149 /* Memory is still inaccessible, breakpoint setting will be deferred again */
150 // KdpDprintf("Failed to set deferred breakpoint at address 0x%p\n",
151 // KdpBreakpointTable[i].Address);
152 KdpOweBreakpoint
= TRUE
;
156 /* Check if we need to write the breakpoint */
157 if (KdpBreakpointTable
[i
].Flags
& KD_BREAKPOINT_PENDING
)
159 /* Memory accessible, set the breakpoint */
160 KdpBreakpointTable
[i
].Content
= Content
;
162 /* Write the breakpoint */
163 Status
= KdpCopyMemoryChunks((ULONG_PTR
)KdpBreakpointTable
[i
].Address
,
164 &KdpBreakpointInstruction
,
167 MMDBG_COPY_UNSAFE
| MMDBG_COPY_WRITE
,
169 if (!NT_SUCCESS(Status
))
171 /* This should never happen */
172 KdpDprintf("Unable to write deferred breakpoint to address 0x%p\n",
173 KdpBreakpointTable
[i
].Address
);
174 KdpOweBreakpoint
= TRUE
;
178 KdpBreakpointTable
[i
].Flags
= KD_BREAKPOINT_ACTIVE
;
184 /* Check if we need to restore the original instruction */
185 if (KdpBreakpointTable
[i
].Flags
& KD_BREAKPOINT_EXPIRED
)
188 Status
= KdpCopyMemoryChunks((ULONG_PTR
)KdpBreakpointTable
[i
].Address
,
189 &KdpBreakpointTable
[i
].Content
,
192 MMDBG_COPY_UNSAFE
| MMDBG_COPY_WRITE
,
194 if (!NT_SUCCESS(Status
))
196 /* This should never happen */
197 KdpDprintf("Unable to delete deferred breakpoint at address 0x%p\n",
198 KdpBreakpointTable
[i
].Address
);
199 KdpOweBreakpoint
= TRUE
;
203 /* Check if the breakpoint is suspended */
204 if (KdpBreakpointTable
[i
].Flags
& KD_BREAKPOINT_SUSPENDED
)
206 KdpBreakpointTable
[i
].Flags
= KD_BREAKPOINT_SUSPENDED
| KD_BREAKPOINT_ACTIVE
;
211 KdpBreakpointTable
[i
].Flags
= 0;
220 /* Exit the debugger */
221 KdExitDebugger(Enable
);
226 KdpLowWriteContent(IN ULONG BpIndex
)
230 /* Make sure that the breakpoint is actually active */
231 if (KdpBreakpointTable
[BpIndex
].Flags
& KD_BREAKPOINT_PENDING
)
233 /* So we have a valid breakpoint, but it hasn't been used yet... */
234 KdpBreakpointTable
[BpIndex
].Flags
&= ~KD_BREAKPOINT_PENDING
;
238 /* Is the original instruction a breakpoint anyway? */
239 if (KdpBreakpointTable
[BpIndex
].Content
== KdpBreakpointInstruction
)
241 /* Then leave it that way... */
245 /* We have an active breakpoint with an instruction to bring back. Do it. */
246 Status
= KdpCopyMemoryChunks((ULONG_PTR
)KdpBreakpointTable
[BpIndex
].Address
,
247 &KdpBreakpointTable
[BpIndex
].Content
,
250 MMDBG_COPY_UNSAFE
| MMDBG_COPY_WRITE
,
252 if (!NT_SUCCESS(Status
))
254 /* Memory is inaccessible now, restoring original instruction is deferred */
255 // KdpDprintf("Failed to delete breakpoint at address 0x%p\n",
256 // KdpBreakpointTable[BpIndex].Address);
257 KdpBreakpointTable
[BpIndex
].Flags
|= KD_BREAKPOINT_EXPIRED
;
258 KdpOweBreakpoint
= TRUE
;
262 /* Everything went fine, return */
268 KdpLowRestoreBreakpoint(IN ULONG BpIndex
)
272 /* Were we not able to remove it earlier? */
273 if (KdpBreakpointTable
[BpIndex
].Flags
& KD_BREAKPOINT_EXPIRED
)
275 /* Just re-use it! */
276 KdpBreakpointTable
[BpIndex
].Flags
&= ~KD_BREAKPOINT_EXPIRED
;
280 /* Are we merely writing a breakpoint on top of another breakpoint? */
281 if (KdpBreakpointTable
[BpIndex
].Content
== KdpBreakpointInstruction
)
287 /* Ok, we actually have to overwrite the instruction now */
288 Status
= KdpCopyMemoryChunks((ULONG_PTR
)KdpBreakpointTable
[BpIndex
].Address
,
289 &KdpBreakpointInstruction
,
292 MMDBG_COPY_UNSAFE
| MMDBG_COPY_WRITE
,
294 if (!NT_SUCCESS(Status
))
296 /* Memory is inaccessible now, restoring breakpoint is deferred */
297 // KdpDprintf("Failed to restore breakpoint at address 0x%p\n",
298 // KdpBreakpointTable[BpIndex].Address);
299 KdpBreakpointTable
[BpIndex
].Flags
|= KD_BREAKPOINT_PENDING
;
300 KdpOweBreakpoint
= TRUE
;
304 /* Clear any possible previous pending flag and return success */
305 KdpBreakpointTable
[BpIndex
].Flags
&= ~KD_BREAKPOINT_PENDING
;
311 KdpDeleteBreakpoint(IN ULONG BpEntry
)
313 ULONG BpIndex
= BpEntry
- 1;
315 /* Check for invalid breakpoint entry */
316 if (!BpEntry
|| (BpEntry
> KD_BREAKPOINT_MAX
)) return FALSE
;
318 /* If the specified breakpoint table entry is not valid, then return FALSE. */
319 if (!KdpBreakpointTable
[BpIndex
].Flags
) return FALSE
;
321 /* Check if the breakpoint is suspended */
322 if (KdpBreakpointTable
[BpIndex
].Flags
& KD_BREAKPOINT_SUSPENDED
)
324 /* Check if breakpoint is not being deleted */
325 if (!(KdpBreakpointTable
[BpIndex
].Flags
& KD_BREAKPOINT_EXPIRED
))
327 /* Invalidate it and return success */
328 KdpBreakpointTable
[BpIndex
].Flags
= 0;
333 /* Restore original data, then invalidate it and return success */
334 if (KdpLowWriteContent(BpIndex
)) KdpBreakpointTable
[BpIndex
].Flags
= 0;
340 KdpDeleteBreakpointRange(IN PVOID Base
,
344 BOOLEAN DeletedBreakpoints
;
346 /* Assume no breakpoints will be deleted */
347 DeletedBreakpoints
= FALSE
;
349 /* Loop the breakpoint table */
350 for (BpIndex
= 0; BpIndex
< KD_BREAKPOINT_MAX
; BpIndex
++)
352 /* Make sure that the breakpoint is active and matches the range. */
353 if ((KdpBreakpointTable
[BpIndex
].Flags
& KD_BREAKPOINT_ACTIVE
) &&
354 ((KdpBreakpointTable
[BpIndex
].Address
>= Base
) &&
355 (KdpBreakpointTable
[BpIndex
].Address
<= Limit
)))
357 /* Delete it, and remember if we succeeded at least once */
358 if (KdpDeleteBreakpoint(BpIndex
+ 1)) DeletedBreakpoints
= TRUE
;
362 /* Return whether we deleted anything */
363 return DeletedBreakpoints
;
368 KdpRestoreAllBreakpoints(VOID
)
372 /* No more suspended Breakpoints */
373 BreakpointsSuspended
= FALSE
;
375 /* Loop the breakpoints */
376 for (BpIndex
= 0; BpIndex
< KD_BREAKPOINT_MAX
; BpIndex
++)
378 /* Check if they are valid, suspended breakpoints */
379 if ((KdpBreakpointTable
[BpIndex
].Flags
& KD_BREAKPOINT_ACTIVE
) &&
380 (KdpBreakpointTable
[BpIndex
].Flags
& KD_BREAKPOINT_SUSPENDED
))
383 KdpBreakpointTable
[BpIndex
].Flags
&= ~KD_BREAKPOINT_SUSPENDED
;
384 KdpLowRestoreBreakpoint(BpIndex
);
391 KdpSuspendBreakPoint(IN ULONG BpEntry
)
393 ULONG BpIndex
= BpEntry
- 1;
395 /* Check if this is a valid, unsuspended breakpoint */
396 if ((KdpBreakpointTable
[BpIndex
].Flags
& KD_BREAKPOINT_ACTIVE
) &&
397 !(KdpBreakpointTable
[BpIndex
].Flags
& KD_BREAKPOINT_SUSPENDED
))
400 KdpBreakpointTable
[BpIndex
].Flags
|= KD_BREAKPOINT_SUSPENDED
;
401 KdpLowWriteContent(BpIndex
);
407 KdpSuspendAllBreakPoints(VOID
)
411 /* Breakpoints are suspended */
412 BreakpointsSuspended
= TRUE
;
414 /* Loop every breakpoint */
415 for (BpEntry
= 1; BpEntry
<= KD_BREAKPOINT_MAX
; BpEntry
++)
418 KdpSuspendBreakPoint(BpEntry
);