ReactOS  0.4.15-dev-1171-gab82533
kdbreak.c
Go to the documentation of this file.
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  * Stefan Ginsberg (stefan.ginsberg@reactos.org)
8  */
9 
10 /* INCLUDES ******************************************************************/
11 
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* FUNCTIONS *****************************************************************/
17 
18 ULONG
19 NTAPI
21 {
22  KD_BREAKPOINT_TYPE Content;
23  ULONG i;
25 
26  /* Check whether we are not setting a breakpoint twice */
27  for (i = 0; i < KD_BREAKPOINT_MAX; i++)
28  {
29  /* Check if the breakpoint is valid */
32  {
33  /* Were we not able to remove it earlier? */
35  {
36  /* Just re-use it! */
38  return i + 1;
39  }
40  else
41  {
42  /* Fail */
43  return 0;
44  }
45  }
46  }
47 
48  /* Find a free entry */
49  for (i = 0; i < KD_BREAKPOINT_MAX; i++)
50  {
51  if (KdpBreakpointTable[i].Flags == 0)
52  break;
53  }
54 
55  /* Fail if no free entry was found */
56  if (i == KD_BREAKPOINT_MAX) return 0;
57 
58  /* Save the breakpoint */
60 
61  /* If we are setting the breakpoint in user space, save the active process context */
63  KdpBreakpointTable[i].DirectoryTableBase = KeGetCurrentThread()->ApcState.Process->DirectoryTableBase[0];
64 
65  /* Try to save the old instruction */
67  &Content,
69  0,
71  NULL);
72  if (NT_SUCCESS(Status))
73  {
74  /* Memory accessible, set the breakpoint */
75  KdpBreakpointTable[i].Content = Content;
77 
78  /* Write the breakpoint */
82  0,
84  NULL);
85  if (!NT_SUCCESS(Status))
86  {
87  /* This should never happen */
88  KdpDprintf("Unable to write breakpoint to address 0x%p\n", Address);
89  }
90  }
91  else
92  {
93  /* Memory is inaccessible now, setting breakpoint is deferred */
94  KdpDprintf("Failed to set breakpoint at address 0x%p, adding deferred breakpoint.\n", Address);
97  }
98 
99  /* Return the breakpoint handle */
100  return i + 1;
101 }
102 
103 VOID
104 NTAPI
106 {
107  BOOLEAN Enable;
108  KD_BREAKPOINT_TYPE Content;
109  ULONG i;
111 
112  /* If we don't owe any breakpoints, just return */
113  if (!KdpOweBreakpoint) return;
114 
115  /* Enter the debugger */
117 
118  /*
119  * Suppose we succeed in setting all the breakpoints.
120  * If we fail to do so, the flag will be set again.
121  */
123 
124  /* Loop through current breakpoints and try to set or delete the pending ones */
125  for (i = 0; i < KD_BREAKPOINT_MAX; i++)
126  {
128  {
129  /*
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.
132  */
134  KdpBreakpointTable[i].DirectoryTableBase != KeGetCurrentThread()->ApcState.Process->DirectoryTableBase[0])
135  {
137  continue;
138  }
139 
140  /* Try to save the old instruction */
142  &Content,
144  0,
146  NULL);
147  if (!NT_SUCCESS(Status))
148  {
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);
153  continue;
154  }
155 
156  /* Check if we need to write the breakpoint */
158  {
159  /* Memory accessible, set the breakpoint */
160  KdpBreakpointTable[i].Content = Content;
161 
162  /* Write the breakpoint */
166  0,
168  NULL);
169  if (!NT_SUCCESS(Status))
170  {
171  /* This should never happen */
172  KdpDprintf("Unable to write deferred breakpoint to address 0x%p\n",
175  }
176  else
177  {
179  }
180 
181  continue;
182  }
183 
184  /* Check if we need to restore the original instruction */
186  {
187  /* Write it back */
189  &KdpBreakpointTable[i].Content,
191  0,
193  NULL);
194  if (!NT_SUCCESS(Status))
195  {
196  /* This should never happen */
197  KdpDprintf("Unable to delete deferred breakpoint at address 0x%p\n",
200  }
201  else
202  {
203  /* Check if the breakpoint is suspended */
205  {
207  }
208  else
209  {
210  /* Invalidate it */
212  }
213  }
214 
215  continue;
216  }
217  }
218  }
219 
220  /* Exit the debugger */
222 }
223 
224 BOOLEAN
225 NTAPI
227 {
229 
230  /* Make sure that the breakpoint is actually active */
232  {
233  /* So we have a valid breakpoint, but it hasn't been used yet... */
235  return TRUE;
236  }
237 
238  /* Is the original instruction a breakpoint anyway? */
239  if (KdpBreakpointTable[BpIndex].Content == KdpBreakpointInstruction)
240  {
241  /* Then leave it that way... */
242  return TRUE;
243  }
244 
245  /* We have an active breakpoint with an instruction to bring back. Do it. */
247  &KdpBreakpointTable[BpIndex].Content,
249  0,
251  NULL);
252  if (!NT_SUCCESS(Status))
253  {
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);
259  return FALSE;
260  }
261 
262  /* Everything went fine, return */
263  return TRUE;
264 }
265 
266 BOOLEAN
267 NTAPI
269 {
271 
272  /* Were we not able to remove it earlier? */
274  {
275  /* Just re-use it! */
277  return TRUE;
278  }
279 
280  /* Are we merely writing a breakpoint on top of another breakpoint? */
281  if (KdpBreakpointTable[BpIndex].Content == KdpBreakpointInstruction)
282  {
283  /* Nothing to do */
284  return TRUE;
285  }
286 
287  /* Ok, we actually have to overwrite the instruction now */
291  0,
293  NULL);
294  if (!NT_SUCCESS(Status))
295  {
296  /* Memory is inaccessible now, restoring breakpoint is deferred */
297  // KdpDprintf("Failed to restore breakpoint at address 0x%p\n",
298  // KdpBreakpointTable[BpIndex].Address);
301  return FALSE;
302  }
303 
304  /* Clear any possible previous pending flag and return success */
306  return TRUE;
307 }
308 
309 BOOLEAN
310 NTAPI
312 {
313  ULONG BpIndex = BpEntry - 1;
314 
315  /* Check for invalid breakpoint entry */
316  if (!BpEntry || (BpEntry > KD_BREAKPOINT_MAX)) return FALSE;
317 
318  /* If the specified breakpoint table entry is not valid, then return FALSE. */
319  if (!KdpBreakpointTable[BpIndex].Flags) return FALSE;
320 
321  /* Check if the breakpoint is suspended */
323  {
324  /* Check if breakpoint is not being deleted */
326  {
327  /* Invalidate it and return success */
328  KdpBreakpointTable[BpIndex].Flags = 0;
329  return TRUE;
330  }
331  }
332 
333  /* Restore original data, then invalidate it and return success */
334  if (KdpLowWriteContent(BpIndex)) KdpBreakpointTable[BpIndex].Flags = 0;
335  return TRUE;
336 }
337 
338 BOOLEAN
339 NTAPI
341  IN PVOID Limit)
342 {
343  ULONG BpIndex;
344  BOOLEAN DeletedBreakpoints;
345 
346  /* Assume no breakpoints will be deleted */
347  DeletedBreakpoints = FALSE;
348 
349  /* Loop the breakpoint table */
350  for (BpIndex = 0; BpIndex < KD_BREAKPOINT_MAX; BpIndex++)
351  {
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)))
356  {
357  /* Delete it, and remember if we succeeded at least once */
358  if (KdpDeleteBreakpoint(BpIndex + 1)) DeletedBreakpoints = TRUE;
359  }
360  }
361 
362  /* Return whether we deleted anything */
363  return DeletedBreakpoints;
364 }
365 
366 VOID
367 NTAPI
369 {
370  ULONG BpIndex;
371 
372  /* No more suspended Breakpoints */
374 
375  /* Loop the breakpoints */
376  for (BpIndex = 0; BpIndex < KD_BREAKPOINT_MAX; BpIndex++)
377  {
378  /* Check if they are valid, suspended breakpoints */
379  if ((KdpBreakpointTable[BpIndex].Flags & KD_BREAKPOINT_ACTIVE) &&
381  {
382  /* Unsuspend them */
384  KdpLowRestoreBreakpoint(BpIndex);
385  }
386  }
387 }
388 
389 VOID
390 NTAPI
392 {
393  ULONG BpIndex = BpEntry - 1;
394 
395  /* Check if this is a valid, unsuspended breakpoint */
396  if ((KdpBreakpointTable[BpIndex].Flags & KD_BREAKPOINT_ACTIVE) &&
398  {
399  /* Suspend it */
401  KdpLowWriteContent(BpIndex);
402  }
403 }
404 
405 VOID
406 NTAPI
408 {
409  ULONG BpEntry;
410 
411  /* Breakpoints are suspended */
413 
414  /* Loop every breakpoint */
415  for (BpEntry = 1; BpEntry <= KD_BREAKPOINT_MAX; BpEntry++)
416  {
417  /* Suspend it */
418  KdpSuspendBreakPoint(BpEntry);
419  }
420 }
VOID NTAPI KdpRestoreAllBreakpoints(VOID)
Definition: kdbreak.c:368
#define IN
Definition: typedefs.h:39
VOID NTAPI KdpSuspendAllBreakPoints(VOID)
Definition: kdbreak.c:407
NTSTATUS NTAPI KdpCopyMemoryChunks(_In_ ULONG64 Address, _In_ PVOID Buffer, _In_ ULONG TotalSize, _In_ ULONG ChunkSize, _In_ ULONG Flags, _Out_opt_ PULONG ActualSize)
Definition: kdapi.c:50
#define TRUE
Definition: types.h:120
ULONG NTAPI KdpAddBreakpoint(IN PVOID Address)
Definition: kdbreak.c:20
LONG NTSTATUS
Definition: precomp.h:26
_In_ ULONGLONG _In_ ULONGLONG _In_ BOOLEAN Enable
Definition: ntddpcm.h:140
_In_opt_ ULONG Base
Definition: rtlfuncs.h:2373
#define KD_BREAKPOINT_SUSPENDED
Definition: kd64.h:42
VOID NTAPI KdExitDebugger(IN BOOLEAN Enable)
Definition: kdmain.c:320
BOOLEAN BreakpointsSuspended
Definition: kddata.c:103
BOOLEAN NTAPI KdpDeleteBreakpoint(IN ULONG BpEntry)
Definition: kdbreak.c:311
uint32_t ULONG_PTR
Definition: typedefs.h:65
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define FALSE
Definition: types.h:117
ULONG_PTR DirectoryTableBase
Definition: kd64.h:51
BOOLEAN KdpOweBreakpoint
Definition: kddata.c:102
BOOLEAN NTAPI KdpLowWriteContent(IN ULONG BpIndex)
Definition: kdbreak.c:226
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
static WCHAR Address[46]
Definition: ping.c:68
#define MMDBG_COPY_WRITE
Definition: mm.h:53
ULONG Flags
Definition: kd64.h:50
#define KD_BREAKPOINT_PENDING
Definition: kd64.h:41
#define KD_HIGHEST_USER_BREAKPOINT_ADDRESS
Definition: kd64.h:35
BOOLEAN NTAPI KdpDeleteBreakpointRange(IN PVOID Base, IN PVOID Limit)
Definition: kdbreak.c:340
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
BOOLEAN NTAPI KdpLowRestoreBreakpoint(IN ULONG BpIndex)
Definition: kdbreak.c:268
KD_BREAKPOINT_TYPE Content
Definition: kd64.h:53
VOID NTAPI KdSetOwedBreakpoints(VOID)
Definition: kdbreak.c:105
KD_BREAKPOINT_TYPE KdpBreakpointInstruction
Definition: kddata.c:101
Status
Definition: gdiplustypes.h:24
#define KD_BREAKPOINT_MAX
Definition: kd64.h:23
#define KD_BREAKPOINT_TYPE
Definition: ke.h:117
VOID NTAPI KdpSuspendBreakPoint(IN ULONG BpEntry)
Definition: kdbreak.c:391
#define MMDBG_COPY_UNSAFE
Definition: mm.h:55
_Out_ PKAPC_STATE ApcState
Definition: mm.h:1492
BREAKPOINT_ENTRY KdpBreakpointTable[KD_BREAKPOINT_MAX]
Definition: kddata.c:100
#define KdpDprintf
Definition: mmdbg.c:19
PVOID Address
Definition: kd64.h:52
unsigned int ULONG
Definition: retypes.h:1
BOOLEAN NTAPI KdEnterDebugger(IN PKTRAP_FRAME TrapFrame, IN PKEXCEPTION_FRAME ExceptionFrame)
Definition: kdmain.c:312
#define KD_BREAKPOINT_SIZE
Definition: ke.h:118
#define KeGetCurrentThread
Definition: hal.h:44
_In_ LONG _In_ LONG Limit
Definition: kefuncs.h:315
#define KD_BREAKPOINT_EXPIRED
Definition: kd64.h:43
#define KD_BREAKPOINT_ACTIVE
Definition: kd64.h:40