xref: /reactos/ntoskrnl/kdbg/kdb.c (revision 7d2f6b65)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS kernel
4  * FILE:            ntoskrnl/kdbg/kdb.c
5  * PURPOSE:         Kernel Debugger
6  *
7  * PROGRAMMERS:     Gregor Anich
8  */
9 
10 /* INCLUDES ******************************************************************/
11 
12 #include <ntoskrnl.h>
13 #include "kdb.h"
14 
15 /* TYPES *********************************************************************/
16 
17 /* DEFINES *******************************************************************/
18 
19 #define KDB_STACK_SIZE                   (4096*3)
20 #ifdef _M_AMD64
21 #define KDB_STACK_ALIGN                 16
22 #define KDB_STACK_RESERVE               (5 * sizeof(PVOID)) /* Home space + return address */
23 #else
24 #define KDB_STACK_ALIGN                 4
25 #define KDB_STACK_RESERVE               sizeof(ULONG) /* Return address */
26 #endif
27 #define KDB_MAXIMUM_BREAKPOINT_COUNT     256
28 #define KDB_MAXIMUM_HW_BREAKPOINT_COUNT  4
29 #define KDB_MAXIMUM_SW_BREAKPOINT_COUNT  256
30 
31 #define __STRING(x) #x
32 #define _STRING(x) __STRING(x)
33 
34 /* GLOBALS *******************************************************************/
35 
36 static LONG KdbEntryCount = 0;
37 static DECLSPEC_ALIGN(KDB_STACK_ALIGN) CHAR KdbStack[KDB_STACK_SIZE];
38 
39 static ULONG KdbBreakPointCount = 0;  /* Number of used breakpoints in the array */
40 static KDB_BREAKPOINT KdbBreakPoints[KDB_MAXIMUM_BREAKPOINT_COUNT] = {{0}};  /* Breakpoint array */
41 static ULONG KdbSwBreakPointCount = 0;  /* Number of enabled software breakpoints */
42 static ULONG KdbHwBreakPointCount = 0;  /* Number of enabled hardware breakpoints */
43 static PKDB_BREAKPOINT KdbSwBreakPoints[KDB_MAXIMUM_SW_BREAKPOINT_COUNT]; /* Enabled software breakpoints, orderless */
44 static PKDB_BREAKPOINT KdbHwBreakPoints[KDB_MAXIMUM_HW_BREAKPOINT_COUNT]; /* Enabled hardware breakpoints, orderless */
45 static PKDB_BREAKPOINT KdbBreakPointToReenable = NULL; /* Set to a breakpoint struct when single stepping after
46                                                           a software breakpoint was hit, to reenable it */
47 static BOOLEAN KdbpEvenThoughWeHaveABreakPointToReenableWeAlsoHaveARealSingleStep;
48 LONG KdbLastBreakPointNr = -1;  /* Index of the breakpoint which cause KDB to be entered */
49 ULONG KdbNumSingleSteps = 0; /* How many single steps to do */
50 BOOLEAN KdbSingleStepOver = FALSE; /* Whether to step over calls/reps. */
51 static BOOLEAN KdbEnteredOnSingleStep = FALSE; /* Set to true when KDB was entered because of single step */
52 PEPROCESS KdbCurrentProcess = NULL;  /* The current process context in which KDB runs */
53 PEPROCESS KdbOriginalProcess = NULL; /* The process in whichs context KDB was intered */
54 PETHREAD KdbCurrentThread = NULL;  /* The current thread context in which KDB runs */
55 PETHREAD KdbOriginalThread = NULL; /* The thread in whichs context KDB was entered */
56 PKDB_KTRAP_FRAME KdbCurrentTrapFrame = NULL; /* Pointer to the current trapframe */
57 static KDB_KTRAP_FRAME KdbTrapFrame = { 0 };  /* The trapframe which was passed to KdbEnterDebuggerException */
58 static KDB_KTRAP_FRAME KdbThreadTrapFrame = { 0 }; /* The trapframe of the current thread (KdbCurrentThread) */
59 static KAPC_STATE KdbApcState;
60 extern BOOLEAN KdbpBugCheckRequested;
61 
62 /* Array of conditions when to enter KDB */
63 static KDB_ENTER_CONDITION KdbEnterConditions[][2] =
64 {
65     /* First chance       Last chance */
66     { KdbDoNotEnter,      KdbEnterFromKmode },   /* 0: Zero divide */
67     { KdbEnterFromKmode,  KdbDoNotEnter },       /* 1: Debug trap */
68     { KdbDoNotEnter,      KdbEnterAlways },      /* 2: NMI */
69     { KdbEnterFromKmode,  KdbDoNotEnter },       /* 3: INT3 */
70     { KdbDoNotEnter,      KdbEnterFromKmode },   /* 4: Overflow */
71     { KdbDoNotEnter,      KdbEnterFromKmode },   /* 5: BOUND range exceeded */
72     { KdbDoNotEnter,      KdbEnterFromKmode },   /* 6: Invalid opcode */
73     { KdbDoNotEnter,      KdbEnterFromKmode },   /* 7: No math coprocessor fault */
74     { KdbEnterAlways,     KdbEnterAlways },      /* 8: Double Fault */
75     { KdbEnterAlways,     KdbEnterAlways },      /* 9: Unknown(9) */
76     { KdbDoNotEnter,      KdbEnterFromKmode },   /* 10: Invalid TSS */
77     { KdbDoNotEnter,      KdbEnterFromKmode },   /* 11: Segment Not Present */
78     { KdbDoNotEnter,      KdbEnterFromKmode },   /* 12: Stack fault */
79     { KdbDoNotEnter,      KdbEnterFromKmode },   /* 13: General protection fault */
80     { KdbDoNotEnter,      KdbEnterFromKmode },   /* 14: Page fault */
81     { KdbEnterAlways,     KdbEnterAlways },      /* 15: Reserved (15) */
82     { KdbDoNotEnter,      KdbEnterFromKmode },   /* 16: FPU fault */
83     { KdbDoNotEnter,      KdbEnterFromKmode },   /* 17: Alignment Check */
84     { KdbDoNotEnter,      KdbEnterFromKmode },   /* 18: Machine Check */
85     { KdbDoNotEnter,      KdbEnterFromKmode },   /* 19: SIMD fault */
86     { KdbEnterFromKmode,  KdbDoNotEnter },       /* 20: Assertion failure */
87     { KdbDoNotEnter,      KdbEnterFromKmode }    /* Last entry: used for unknown exceptions */
88 };
89 
90 /* Exception descriptions */
91 static const CHAR *ExceptionNrToString[] =
92 {
93     "Divide Error",
94     "Debug Trap",
95     "NMI",
96     "Breakpoint",
97     "Overflow",
98     "BOUND range exceeded",
99     "Invalid Opcode",
100     "No Math Coprocessor",
101     "Double Fault",
102     "Unknown(9)",
103     "Invalid TSS",
104     "Segment Not Present",
105     "Stack Segment Fault",
106     "General Protection",
107     "Page Fault",
108     "Reserved(15)",
109     "Math Fault",
110     "Alignment Check",
111     "Machine Check",
112     "SIMD Fault",
113     "Assertion Failure"
114 };
115 
116 /* FUNCTIONS *****************************************************************/
117 
118 static VOID
119 KdbpKdbTrapFrameFromKernelStack(
120     PVOID KernelStack,
121     PKDB_KTRAP_FRAME KdbTrapFrame)
122 {
123     ULONG_PTR *StackPtr;
124 
125     RtlZeroMemory(KdbTrapFrame, sizeof(KDB_KTRAP_FRAME));
126     StackPtr = (ULONG_PTR *) KernelStack;
127 #ifdef _M_IX86
128     KdbTrapFrame->Ebp = StackPtr[3];
129     KdbTrapFrame->Edi = StackPtr[4];
130     KdbTrapFrame->Esi = StackPtr[5];
131     KdbTrapFrame->Ebx = StackPtr[6];
132     KdbTrapFrame->Eip = StackPtr[7];
133     KdbTrapFrame->Esp = (ULONG) (StackPtr + 8);
134     KdbTrapFrame->SegSs = KGDT_R0_DATA;
135     KdbTrapFrame->SegCs = KGDT_R0_CODE;
136     KdbTrapFrame->SegDs = KGDT_R0_DATA;
137     KdbTrapFrame->SegEs = KGDT_R0_DATA;
138     KdbTrapFrame->SegGs = KGDT_R0_DATA;
139 #endif
140 
141     /* FIXME: what about the other registers??? */
142 }
143 
144 /*!\brief Overwrites the instruction at \a Address with \a NewInst and stores
145  *        the old instruction in *OldInst.
146  *
147  * \param Process  Process in which's context to overwrite the instruction.
148  * \param Address  Address at which to overwrite the instruction.
149  * \param NewInst  New instruction (written to \a Address)
150  * \param OldInst  Old instruction (read from \a Address)
151  *
152  * \returns NTSTATUS
153  */
154 static NTSTATUS
155 KdbpOverwriteInstruction(
156     IN  PEPROCESS Process,
157     IN  ULONG_PTR Address,
158     IN  UCHAR NewInst,
159     OUT PUCHAR OldInst  OPTIONAL)
160 {
161     NTSTATUS Status;
162     ULONG Protect;
163     PEPROCESS CurrentProcess = PsGetCurrentProcess();
164     KAPC_STATE ApcState;
165 
166     /* Get the protection for the address. */
167     Protect = MmGetPageProtect(Process, (PVOID)PAGE_ROUND_DOWN(Address));
168 
169     /* Return if that page isn't present. */
170     if (Protect & PAGE_NOACCESS)
171     {
172         return STATUS_MEMORY_NOT_ALLOCATED;
173     }
174 
175     /* Attach to the process */
176     if (CurrentProcess != Process)
177     {
178         KeStackAttachProcess(&Process->Pcb, &ApcState);
179     }
180 
181     /* Make the page writeable if it is read only. */
182     if (Protect & (PAGE_READONLY|PAGE_EXECUTE|PAGE_EXECUTE_READ))
183     {
184         MmSetPageProtect(Process, (PVOID)PAGE_ROUND_DOWN(Address),
185                          (Protect & ~(PAGE_READONLY|PAGE_EXECUTE|PAGE_EXECUTE_READ)) | PAGE_READWRITE);
186     }
187 
188     /* Copy the old instruction back to the caller. */
189     if (OldInst)
190     {
191         Status = KdbpSafeReadMemory(OldInst, (PUCHAR)Address, 1);
192         if (!NT_SUCCESS(Status))
193         {
194             if (Protect & (PAGE_READONLY|PAGE_EXECUTE|PAGE_EXECUTE_READ))
195             {
196                 MmSetPageProtect(Process, (PVOID)PAGE_ROUND_DOWN(Address), Protect);
197             }
198 
199             /* Detach from process */
200             if (CurrentProcess != Process)
201             {
202                 KeUnstackDetachProcess(&ApcState);
203             }
204 
205             return Status;
206         }
207     }
208 
209     /* Copy the new instruction in its place. */
210     Status = KdbpSafeWriteMemory((PUCHAR)Address, &NewInst, 1);
211 
212     /* Restore the page protection. */
213     if (Protect & (PAGE_READONLY|PAGE_EXECUTE|PAGE_EXECUTE_READ))
214     {
215         MmSetPageProtect(Process, (PVOID)PAGE_ROUND_DOWN(Address), Protect);
216     }
217 
218     /* Detach from process */
219     if (CurrentProcess != Process)
220     {
221         KeUnstackDetachProcess(&ApcState);
222     }
223 
224     return Status;
225 }
226 
227 /*!\brief Checks whether the given instruction can be single stepped or has to be
228  *        stepped over using a temporary breakpoint.
229  *
230  * \retval TRUE   Instruction is a call.
231  * \retval FALSE  Instruction is not a call.
232  */
233 BOOLEAN
234 KdbpShouldStepOverInstruction(
235     ULONG_PTR Eip)
236 {
237     UCHAR Mem[3];
238     ULONG i = 0;
239 
240     if (!NT_SUCCESS(KdbpSafeReadMemory(Mem, (PVOID)Eip, sizeof (Mem))))
241     {
242         KdbPrintf("Couldn't access memory at 0x%p\n", Eip);
243         return FALSE;
244     }
245 
246     /* Check if the current instruction is a call. */
247     while ((i < sizeof (Mem)) && (Mem[i] == 0x66 || Mem[i] == 0x67))
248         i++;
249 
250     if (i == sizeof (Mem))
251         return FALSE;
252 
253     if (Mem[i] == 0xE8 || Mem[i] == 0x9A || Mem[i] == 0xF2 || Mem[i] == 0xF3 ||
254         (((i + 1) < sizeof (Mem)) && Mem[i] == 0xFF && (Mem[i+1] & 0x38) == 0x10))
255     {
256         return TRUE;
257     }
258 
259     return FALSE;
260 }
261 
262 /*!\brief Steps over an instruction
263  *
264  * If the given instruction should be stepped over, this function inserts a
265  * temporary breakpoint after the instruction and returns TRUE, otherwise it
266  * returns FALSE.
267  *
268  * \retval TRUE   Temporary breakpoint set after instruction.
269  * \retval FALSE  No breakpoint was set.
270  */
271 BOOLEAN
272 KdbpStepOverInstruction(
273     ULONG_PTR Eip)
274 {
275     LONG InstLen;
276 
277     if (!KdbpShouldStepOverInstruction(Eip))
278         return FALSE;
279 
280     InstLen = KdbpGetInstLength(Eip);
281     if (InstLen < 1)
282         return FALSE;
283 
284     if (!NT_SUCCESS(KdbpInsertBreakPoint(Eip + InstLen, KdbBreakPointTemporary, 0, 0, NULL, FALSE, NULL)))
285         return FALSE;
286 
287     return TRUE;
288 }
289 
290 /*!\brief Steps into an instruction (interrupts)
291  *
292  * If the given instruction should be stepped into, this function inserts a
293  * temporary breakpoint at the target instruction and returns TRUE, otherwise it
294  * returns FALSE.
295  *
296  * \retval TRUE   Temporary breakpoint set at target instruction.
297  * \retval FALSE  No breakpoint was set.
298  */
299 BOOLEAN
300 KdbpStepIntoInstruction(
301     ULONG_PTR Eip)
302 {
303     KDESCRIPTOR Idtr = {0};
304     UCHAR Mem[2];
305     INT IntVect;
306     ULONG IntDesc[2];
307     ULONG_PTR TargetEip;
308 
309     /* Read memory */
310     if (!NT_SUCCESS(KdbpSafeReadMemory(Mem, (PVOID)Eip, sizeof (Mem))))
311     {
312         // KdbPrintf("Couldn't access memory at 0x%p\n", Eip);
313         return FALSE;
314     }
315 
316     /* Check for INT instruction */
317     /* FIXME: Check for iret */
318     if (Mem[0] == 0xcc)
319         IntVect = 3;
320     else if (Mem[0] == 0xcd)
321         IntVect = Mem[1];
322     else if (Mem[0] == 0xce && KdbCurrentTrapFrame->EFlags & (1<<11)) /* 1 << 11 is the overflow flag */
323         IntVect = 4;
324     else
325         return FALSE;
326 
327     if (IntVect < 32) /* We should be informed about interrupts < 32 by the kernel, no need to breakpoint them */
328     {
329         return FALSE;
330     }
331 
332     /* Read the interrupt descriptor table register  */
333     __sidt(&Idtr.Limit);
334     if (IntVect >= (Idtr.Limit + 1) / 8)
335     {
336         // KdbPrintf("IDT does not contain interrupt vector %d.\n", IntVect);
337         return TRUE;
338     }
339 
340     /* Get the interrupt descriptor */
341     if (!NT_SUCCESS(KdbpSafeReadMemory(IntDesc, (PVOID)((ULONG_PTR)Idtr.Base + (IntVect * 8)), sizeof(IntDesc))))
342     {
343         // KdbPrintf("Couldn't access memory at 0x%p\n", (ULONG_PTR)Idtr.Base + (IntVect * 8));
344         return FALSE;
345     }
346 
347     /* Check descriptor and get target eip (16 bit interrupt/trap gates not supported) */
348     if ((IntDesc[1] & (1 << 15)) == 0) /* not present */
349     {
350         return FALSE;
351     }
352     if ((IntDesc[1] & 0x1f00) == 0x0500) /* Task gate */
353     {
354         /* FIXME: Task gates not supported */
355         return FALSE;
356     }
357     else if (((IntDesc[1] & 0x1fe0) == 0x0e00) || /* 32 bit Interrupt gate */
358              ((IntDesc[1] & 0x1fe0) == 0x0f00))   /* 32 bit Trap gate */
359     {
360         /* FIXME: Should the segment selector of the interrupt gate be checked? */
361         TargetEip = (IntDesc[1] & 0xffff0000) | (IntDesc[0] & 0x0000ffff);
362     }
363     else
364     {
365         return FALSE;
366     }
367 
368     /* Insert breakpoint */
369     if (!NT_SUCCESS(KdbpInsertBreakPoint(TargetEip, KdbBreakPointTemporary, 0, 0, NULL, FALSE, NULL)))
370         return FALSE;
371 
372     return TRUE;
373 }
374 
375 /*!\brief Gets the number of the next breakpoint >= Start.
376  *
377  * \param Start   Breakpoint number to start searching at. -1 if no more breakpoints are found.
378  *
379  * \returns Breakpoint number (-1 if no more breakpoints are found)
380  */
381 LONG
382 KdbpGetNextBreakPointNr(
383     IN ULONG Start  OPTIONAL)
384 {
385     for (; Start < RTL_NUMBER_OF(KdbBreakPoints); Start++)
386     {
387         if (KdbBreakPoints[Start].Type != KdbBreakPointNone)
388             return Start;
389     }
390 
391     return -1;
392 }
393 
394 /*!\brief Returns information of the specified breakpoint.
395  *
396  * \param BreakPointNr         Number of the breakpoint to return information of.
397  * \param Address              Receives the address of the breakpoint.
398  * \param Type                 Receives the type of the breakpoint (hardware or software)
399  * \param Size                 Size - for memory breakpoints.
400  * \param AccessType           Access type - for hardware breakpoints.
401  * \param DebugReg             Debug register - for enabled hardware breakpoints.
402  * \param Enabled              Whether the breakpoint is enabled or not.
403  * \param Process              The owning process of the breakpoint.
404  * \param ConditionExpression  The expression which was given as condition for the bp.
405  *
406  * \returns NULL on failure, pointer to a KDB_BREAKPOINT struct on success.
407  */
408 BOOLEAN
409 KdbpGetBreakPointInfo(
410     IN  ULONG BreakPointNr,
411     OUT ULONG_PTR *Address  OPTIONAL,
412     OUT KDB_BREAKPOINT_TYPE *Type  OPTIONAL,
413     OUT UCHAR *Size  OPTIONAL,
414     OUT KDB_ACCESS_TYPE *AccessType  OPTIONAL,
415     OUT UCHAR *DebugReg  OPTIONAL,
416     OUT BOOLEAN *Enabled  OPTIONAL,
417     OUT BOOLEAN *Global  OPTIONAL,
418     OUT PEPROCESS *Process  OPTIONAL,
419     OUT PCHAR *ConditionExpression  OPTIONAL)
420 {
421     PKDB_BREAKPOINT bp;
422 
423     if (BreakPointNr >= RTL_NUMBER_OF(KdbBreakPoints) ||
424         KdbBreakPoints[BreakPointNr].Type == KdbBreakPointNone)
425     {
426         return FALSE;
427     }
428 
429     bp = KdbBreakPoints + BreakPointNr;
430     if (Address)
431         *Address = bp->Address;
432 
433     if (Type)
434         *Type = bp->Type;
435 
436     if (bp->Type == KdbBreakPointHardware)
437     {
438         if (Size)
439             *Size = bp->Data.Hw.Size;
440 
441         if (AccessType)
442             *AccessType = bp->Data.Hw.AccessType;
443 
444         if (DebugReg && bp->Enabled)
445             *DebugReg = bp->Data.Hw.DebugReg;
446     }
447 
448     if (Enabled)
449         *Enabled = bp->Enabled;
450 
451     if (Global)
452         *Global = bp->Global;
453 
454     if (Process)
455         *Process = bp->Process;
456 
457     if (ConditionExpression)
458         *ConditionExpression = bp->ConditionExpression;
459 
460     return TRUE;
461 }
462 
463 /*!\brief Inserts a breakpoint into the breakpoint array.
464  *
465  * The \a Process of the breakpoint is set to \a KdbCurrentProcess
466  *
467  * \param Address              Address at which to set the breakpoint.
468  * \param Type                 Type of breakpoint (hardware or software)
469  * \param Size                 Size of breakpoint (for hardware/memory breakpoints)
470  * \param AccessType           Access type (for hardware breakpoins)
471  * \param ConditionExpression  Expression which must evaluate to true for conditional breakpoints.
472  * \param Global               Wether the breakpoint is global or local to a process.
473  * \param BreakPointNumber     Receives the breakpoint number on success
474  *
475  * \returns NTSTATUS
476  */
477 NTSTATUS
478 KdbpInsertBreakPoint(
479     IN  ULONG_PTR Address,
480     IN  KDB_BREAKPOINT_TYPE Type,
481     IN  UCHAR Size  OPTIONAL,
482     IN  KDB_ACCESS_TYPE AccessType  OPTIONAL,
483     IN  PCHAR ConditionExpression  OPTIONAL,
484     IN  BOOLEAN Global,
485     OUT PLONG BreakPointNr  OPTIONAL)
486 {
487     LONG_PTR i;
488     PVOID Condition;
489     PCHAR ConditionExpressionDup;
490     LONG ErrOffset;
491     CHAR ErrMsg[128];
492 
493     ASSERT(Type != KdbBreakPointNone);
494 
495     if (Type == KdbBreakPointHardware)
496     {
497         if ((Address % Size) != 0)
498         {
499             KdbPrintf("Address (0x%p) must be aligned to a multiple of the size (%d)\n", Address, Size);
500             return STATUS_UNSUCCESSFUL;
501         }
502 
503         if (AccessType == KdbAccessExec && Size != 1)
504         {
505             KdbPuts("Size must be 1 for execution breakpoints.\n");
506             return STATUS_UNSUCCESSFUL;
507         }
508     }
509 
510     if (KdbBreakPointCount == KDB_MAXIMUM_BREAKPOINT_COUNT)
511     {
512         return STATUS_UNSUCCESSFUL;
513     }
514 
515     /* Parse condition expression string and duplicate it */
516     if (ConditionExpression)
517     {
518         Condition = KdbpRpnParseExpression(ConditionExpression, &ErrOffset, ErrMsg);
519         if (!Condition)
520         {
521             if (ErrOffset >= 0)
522                 KdbPrintf("Couldn't parse expression: %s at character %d\n", ErrMsg, ErrOffset);
523             else
524                 KdbPrintf("Couldn't parse expression: %s", ErrMsg);
525 
526             return STATUS_UNSUCCESSFUL;
527         }
528 
529         i = strlen(ConditionExpression) + 1;
530         ConditionExpressionDup = ExAllocatePoolWithTag(NonPagedPool, i, TAG_KDBG);
531         RtlCopyMemory(ConditionExpressionDup, ConditionExpression, i);
532     }
533     else
534     {
535         Condition = NULL;
536         ConditionExpressionDup = NULL;
537     }
538 
539     /* Find unused breakpoint */
540     if (Type == KdbBreakPointTemporary)
541     {
542         for (i = RTL_NUMBER_OF(KdbBreakPoints) - 1; i >= 0; i--)
543         {
544             if (KdbBreakPoints[i].Type == KdbBreakPointNone)
545                 break;
546         }
547     }
548     else
549     {
550         for (i = 0; i < (LONG)RTL_NUMBER_OF(KdbBreakPoints); i++)
551         {
552             if (KdbBreakPoints[i].Type == KdbBreakPointNone)
553                 break;
554         }
555     }
556 
557     ASSERT(i < (LONG)RTL_NUMBER_OF(KdbBreakPoints));
558 
559     /* Set the breakpoint */
560     ASSERT(KdbCurrentProcess);
561     KdbBreakPoints[i].Type = Type;
562     KdbBreakPoints[i].Address = Address;
563     KdbBreakPoints[i].Enabled = FALSE;
564     KdbBreakPoints[i].Global = Global;
565     KdbBreakPoints[i].Process = KdbCurrentProcess;
566     KdbBreakPoints[i].ConditionExpression = ConditionExpressionDup;
567     KdbBreakPoints[i].Condition = Condition;
568 
569     if (Type == KdbBreakPointHardware)
570     {
571         KdbBreakPoints[i].Data.Hw.Size = Size;
572         KdbBreakPoints[i].Data.Hw.AccessType = AccessType;
573     }
574 
575     KdbBreakPointCount++;
576 
577     if (Type != KdbBreakPointTemporary)
578         KdbPrintf("Breakpoint %d inserted.\n", i);
579 
580     /* Try to enable the breakpoint */
581     KdbpEnableBreakPoint(i, NULL);
582 
583     /* Return the breakpoint number */
584     if (BreakPointNr)
585         *BreakPointNr = i;
586 
587     return STATUS_SUCCESS;
588 }
589 
590 /*!\brief Deletes a breakpoint
591  *
592  * \param BreakPointNr  Number of the breakpoint to delete. Can be -1
593  * \param BreakPoint    Breakpoint to delete. Can be NULL.
594  *
595  * \retval TRUE   Success.
596  * \retval FALSE  Failure (invalid breakpoint number)
597  */
598 BOOLEAN
599 KdbpDeleteBreakPoint(
600     IN LONG BreakPointNr  OPTIONAL,
601     IN OUT PKDB_BREAKPOINT BreakPoint  OPTIONAL)
602 {
603     if (BreakPointNr < 0)
604     {
605         ASSERT(BreakPoint);
606         BreakPointNr = BreakPoint - KdbBreakPoints;
607     }
608 
609     if (BreakPointNr < 0 || BreakPointNr >= KDB_MAXIMUM_BREAKPOINT_COUNT)
610     {
611         KdbPrintf("Invalid breakpoint: %d\n", BreakPointNr);
612         return FALSE;
613     }
614 
615     if (!BreakPoint)
616     {
617         BreakPoint = KdbBreakPoints + BreakPointNr;
618     }
619 
620     if (BreakPoint->Type == KdbBreakPointNone)
621     {
622         KdbPrintf("Invalid breakpoint: %d\n", BreakPointNr);
623         return FALSE;
624     }
625 
626     if (BreakPoint->Enabled && !KdbpDisableBreakPoint(-1, BreakPoint))
627         return FALSE;
628 
629     if (BreakPoint->Type != KdbBreakPointTemporary)
630         KdbPrintf("Breakpoint %d deleted.\n", BreakPointNr);
631 
632     BreakPoint->Type = KdbBreakPointNone;
633     KdbBreakPointCount--;
634 
635     return TRUE;
636 }
637 
638 /*!\brief Checks if the breakpoint was set by the debugger
639  *
640  * Tries to find a breakpoint in the breakpoint array which caused
641  * the debug exception to happen.
642  *
643  * \param ExpNr      Exception Number (1 or 3)
644  * \param TrapFrame  Exception trapframe
645  *
646  * \returns Breakpoint number, -1 on error.
647  */
648 static LONG
649 KdbpIsBreakPointOurs(
650     IN NTSTATUS ExceptionCode,
651     IN PCONTEXT Context)
652 {
653     ULONG i;
654     ASSERT(ExceptionCode == STATUS_SINGLE_STEP || ExceptionCode == STATUS_BREAKPOINT);
655 
656     if (ExceptionCode == STATUS_BREAKPOINT) /* Software interrupt */
657     {
658         ULONG_PTR BpPc = KeGetContextPc(Context) - 1; /* Get EIP of INT3 instruction */
659         for (i = 0; i < KdbSwBreakPointCount; i++)
660         {
661             ASSERT((KdbSwBreakPoints[i]->Type == KdbBreakPointSoftware ||
662                    KdbSwBreakPoints[i]->Type == KdbBreakPointTemporary));
663             ASSERT(KdbSwBreakPoints[i]->Enabled);
664 
665             if (KdbSwBreakPoints[i]->Address == BpPc)
666             {
667                 return KdbSwBreakPoints[i] - KdbBreakPoints;
668             }
669         }
670     }
671     else if (ExceptionCode == STATUS_SINGLE_STEP) /* Hardware interrupt */
672     {
673         UCHAR DebugReg;
674 
675         for (i = 0; i < KdbHwBreakPointCount; i++)
676         {
677             ASSERT(KdbHwBreakPoints[i]->Type == KdbBreakPointHardware &&
678                    KdbHwBreakPoints[i]->Enabled);
679             DebugReg = KdbHwBreakPoints[i]->Data.Hw.DebugReg;
680 
681             if ((Context->Dr6 & ((ULONG_PTR)1 << DebugReg)) != 0)
682             {
683                 return KdbHwBreakPoints[i] - KdbBreakPoints;
684             }
685         }
686     }
687 
688     return -1;
689 }
690 
691 /*!\brief Enables a breakpoint.
692  *
693  * \param BreakPointNr  Number of the breakpoint to enable Can be -1.
694  * \param BreakPoint    Breakpoint to enable. Can be NULL.
695  *
696  * \retval TRUE   Success.
697  * \retval FALSE  Failure.
698  *
699  * \sa KdbpDisableBreakPoint
700  */
701 BOOLEAN
702 KdbpEnableBreakPoint(
703     IN LONG BreakPointNr  OPTIONAL,
704     IN OUT PKDB_BREAKPOINT BreakPoint  OPTIONAL)
705 {
706     NTSTATUS Status;
707     INT i;
708     ULONG ul;
709 
710     if (BreakPointNr < 0)
711     {
712         ASSERT(BreakPoint);
713         BreakPointNr = BreakPoint - KdbBreakPoints;
714     }
715 
716     if (BreakPointNr < 0 || BreakPointNr >= KDB_MAXIMUM_BREAKPOINT_COUNT)
717     {
718         KdbPrintf("Invalid breakpoint: %d\n", BreakPointNr);
719         return FALSE;
720     }
721 
722     if (!BreakPoint)
723     {
724         BreakPoint = KdbBreakPoints + BreakPointNr;
725     }
726 
727     if (BreakPoint->Type == KdbBreakPointNone)
728     {
729         KdbPrintf("Invalid breakpoint: %d\n", BreakPointNr);
730         return FALSE;
731     }
732 
733     if (BreakPoint->Enabled)
734     {
735         KdbPrintf("Breakpoint %d is already enabled.\n", BreakPointNr);
736         return TRUE;
737     }
738 
739     if (BreakPoint->Type == KdbBreakPointSoftware ||
740         BreakPoint->Type == KdbBreakPointTemporary)
741     {
742         if (KdbSwBreakPointCount >= KDB_MAXIMUM_SW_BREAKPOINT_COUNT)
743         {
744             KdbPrintf("Maximum number of SW breakpoints (%d) used. "
745                       "Disable another breakpoint in order to enable this one.\n",
746                       KDB_MAXIMUM_SW_BREAKPOINT_COUNT);
747             return FALSE;
748         }
749 
750         Status = KdbpOverwriteInstruction(BreakPoint->Process, BreakPoint->Address,
751                                           0xCC, &BreakPoint->Data.SavedInstruction);
752         if (!NT_SUCCESS(Status))
753         {
754             KdbPrintf("Couldn't access memory at 0x%p\n", BreakPoint->Address);
755             return FALSE;
756         }
757 
758         KdbSwBreakPoints[KdbSwBreakPointCount++] = BreakPoint;
759     }
760     else
761     {
762         if (BreakPoint->Data.Hw.AccessType == KdbAccessExec)
763             ASSERT(BreakPoint->Data.Hw.Size == 1);
764 
765         ASSERT((BreakPoint->Address % BreakPoint->Data.Hw.Size) == 0);
766 
767         if (KdbHwBreakPointCount >= KDB_MAXIMUM_HW_BREAKPOINT_COUNT)
768         {
769             KdbPrintf("Maximum number of HW breakpoints (%d) already used. "
770                       "Disable another breakpoint in order to enable this one.\n",
771                       KDB_MAXIMUM_HW_BREAKPOINT_COUNT);
772             return FALSE;
773         }
774 
775         /* Find unused hw breakpoint */
776         ASSERT(KDB_MAXIMUM_HW_BREAKPOINT_COUNT == 4);
777         for (i = 0; i < KDB_MAXIMUM_HW_BREAKPOINT_COUNT; i++)
778         {
779             if ((KdbTrapFrame.Dr7 & (0x3 << (i * 2))) == 0)
780                 break;
781         }
782 
783         ASSERT(i < KDB_MAXIMUM_HW_BREAKPOINT_COUNT);
784 
785         /* Set the breakpoint address. */
786         switch (i)
787         {
788             case 0:
789                 KdbTrapFrame.Dr0 = BreakPoint->Address;
790                 break;
791             case 1:
792                 KdbTrapFrame.Dr1 = BreakPoint->Address;
793                 break;
794             case 2:
795                 KdbTrapFrame.Dr2 = BreakPoint->Address;
796                 break;
797             case 3:
798                 KdbTrapFrame.Dr3 = BreakPoint->Address;
799                 break;
800         }
801 
802         /* Enable the global breakpoint */
803         KdbTrapFrame.Dr7 |= (0x2 << (i * 2));
804 
805         /* Enable the exact match bits. */
806         KdbTrapFrame.Dr7 |= 0x00000300;
807 
808         /* Clear existing state. */
809         KdbTrapFrame.Dr7 &= ~(0xF << (16 + (i * 4)));
810 
811         /* Set the breakpoint type. */
812         switch (BreakPoint->Data.Hw.AccessType)
813         {
814             case KdbAccessExec:
815                 ul = 0;
816                 break;
817             case KdbAccessWrite:
818                 ul = 1;
819                 break;
820             case KdbAccessRead:
821             case KdbAccessReadWrite:
822                 ul = 3;
823                 break;
824             default:
825                 ASSERT(0);
826                 return TRUE;
827                 break;
828         }
829 
830         KdbTrapFrame.Dr7 |= (ul << (16 + (i * 4)));
831 
832         /* Set the breakpoint length. */
833         KdbTrapFrame.Dr7 |= ((BreakPoint->Data.Hw.Size - 1) << (18 + (i * 4)));
834 
835         /* Update KdbCurrentTrapFrame - values are taken from there by the CLI */
836         if (&KdbTrapFrame != KdbCurrentTrapFrame)
837         {
838             KdbCurrentTrapFrame->Dr0 = KdbTrapFrame.Dr0;
839             KdbCurrentTrapFrame->Dr1 = KdbTrapFrame.Dr1;
840             KdbCurrentTrapFrame->Dr2 = KdbTrapFrame.Dr2;
841             KdbCurrentTrapFrame->Dr3 = KdbTrapFrame.Dr3;
842             KdbCurrentTrapFrame->Dr6 = KdbTrapFrame.Dr6;
843             KdbCurrentTrapFrame->Dr7 = KdbTrapFrame.Dr7;
844         }
845 
846         BreakPoint->Data.Hw.DebugReg = i;
847         KdbHwBreakPoints[KdbHwBreakPointCount++] = BreakPoint;
848     }
849 
850     BreakPoint->Enabled = TRUE;
851     if (BreakPoint->Type != KdbBreakPointTemporary)
852         KdbPrintf("Breakpoint %d enabled.\n", BreakPointNr);
853 
854     return TRUE;
855 }
856 
857 /*!\brief Disables a breakpoint.
858  *
859  * \param BreakPointNr  Number of the breakpoint to disable. Can be -1
860  * \param BreakPoint    Breakpoint to disable. Can be NULL.
861  *
862  * \retval TRUE   Success.
863  * \retval FALSE  Failure.
864  *
865  * \sa KdbpEnableBreakPoint
866  */
867 BOOLEAN
868 KdbpDisableBreakPoint(
869     IN LONG BreakPointNr  OPTIONAL,
870     IN OUT PKDB_BREAKPOINT BreakPoint  OPTIONAL)
871 {
872     ULONG i;
873     NTSTATUS Status;
874 
875     if (BreakPointNr < 0)
876     {
877         ASSERT(BreakPoint);
878         BreakPointNr = BreakPoint - KdbBreakPoints;
879     }
880 
881     if (BreakPointNr < 0 || BreakPointNr >= KDB_MAXIMUM_BREAKPOINT_COUNT)
882     {
883         KdbPrintf("Invalid breakpoint: %d\n", BreakPointNr);
884         return FALSE;
885     }
886 
887     if (!BreakPoint)
888     {
889         BreakPoint = KdbBreakPoints + BreakPointNr;
890     }
891 
892     if (BreakPoint->Type == KdbBreakPointNone)
893     {
894         KdbPrintf("Invalid breakpoint: %d\n", BreakPointNr);
895         return FALSE;
896     }
897 
898     if (BreakPoint->Enabled == FALSE)
899     {
900         KdbPrintf("Breakpoint %d is not enabled.\n", BreakPointNr);
901         return TRUE;
902     }
903 
904     if (BreakPoint->Type == KdbBreakPointSoftware ||
905         BreakPoint->Type == KdbBreakPointTemporary)
906     {
907         ASSERT(KdbSwBreakPointCount > 0);
908         Status = KdbpOverwriteInstruction(BreakPoint->Process, BreakPoint->Address,
909                                           BreakPoint->Data.SavedInstruction, NULL);
910 
911         if (!NT_SUCCESS(Status))
912         {
913             KdbPuts("Couldn't restore original instruction.\n");
914             return FALSE;
915         }
916 
917         for (i = 0; i < KdbSwBreakPointCount; i++)
918         {
919             if (KdbSwBreakPoints[i] == BreakPoint)
920             {
921                 KdbSwBreakPoints[i] = KdbSwBreakPoints[--KdbSwBreakPointCount];
922                 i = -1; /* if the last breakpoint is disabled dont break with i >= KdbSwBreakPointCount */
923                 break;
924             }
925         }
926 
927         if (i != MAXULONG) /* not found */
928             ASSERT(0);
929     }
930     else
931     {
932         ASSERT(BreakPoint->Type == KdbBreakPointHardware);
933 
934         /* Clear the breakpoint. */
935         KdbTrapFrame.Dr7 &= ~(0x3 << (BreakPoint->Data.Hw.DebugReg * 2));
936         if ((KdbTrapFrame.Dr7 & 0xFF) == 0)
937         {
938             /* If no breakpoints are enabled then clear the exact match flags. */
939             KdbTrapFrame.Dr7 &= 0xFFFFFCFF;
940         }
941 
942         for (i = 0; i < KdbHwBreakPointCount; i++)
943         {
944             if (KdbHwBreakPoints[i] == BreakPoint)
945             {
946                 KdbHwBreakPoints[i] = KdbHwBreakPoints[--KdbHwBreakPointCount];
947                 i = -1; /* if the last breakpoint is disabled dont break with i >= KdbHwBreakPointCount */
948                 break;
949             }
950         }
951 
952         if (i != MAXULONG) /* not found */
953             ASSERT(0);
954     }
955 
956     BreakPoint->Enabled = FALSE;
957     if (BreakPoint->Type != KdbBreakPointTemporary)
958         KdbPrintf("Breakpoint %d disabled.\n", BreakPointNr);
959 
960     return TRUE;
961 }
962 
963 /*!\brief Gets the first or last chance enter-condition for exception nr. \a ExceptionNr
964  *
965  * \param ExceptionNr  Number of the exception to get condition of.
966  * \param FirstChance  Whether to get first or last chance condition.
967  * \param Condition    Receives the condition setting.
968  *
969  * \retval TRUE   Success.
970  * \retval FALSE  Failure (invalid exception nr)
971  */
972 BOOLEAN
973 KdbpGetEnterCondition(
974     IN LONG ExceptionNr,
975     IN BOOLEAN FirstChance,
976     OUT KDB_ENTER_CONDITION *Condition)
977 {
978     if (ExceptionNr >= (LONG)RTL_NUMBER_OF(KdbEnterConditions))
979         return FALSE;
980 
981     *Condition = KdbEnterConditions[ExceptionNr][FirstChance ? 0 : 1];
982     return TRUE;
983 }
984 
985 /*!\brief Sets the first or last chance enter-condition for exception nr. \a ExceptionNr
986  *
987  * \param ExceptionNr  Number of the exception to set condition of (-1 for all)
988  * \param FirstChance  Whether to set first or last chance condition.
989  * \param Condition    The new condition setting.
990  *
991  * \retval TRUE   Success.
992  * \retval FALSE  Failure (invalid exception nr)
993  */
994 BOOLEAN
995 KdbpSetEnterCondition(
996     IN LONG ExceptionNr,
997     IN BOOLEAN FirstChance,
998     IN KDB_ENTER_CONDITION Condition)
999 {
1000     if (ExceptionNr < 0)
1001     {
1002         for (ExceptionNr = 0; ExceptionNr < (LONG)RTL_NUMBER_OF(KdbEnterConditions); ExceptionNr++)
1003         {
1004             if (ExceptionNr == 1 || ExceptionNr == 8 ||
1005                 ExceptionNr == 9 || ExceptionNr == 15) /* Reserved exceptions */
1006             {
1007                 continue;
1008             }
1009 
1010             KdbEnterConditions[ExceptionNr][FirstChance ? 0 : 1] = Condition;
1011         }
1012     }
1013     else
1014     {
1015         if (ExceptionNr >= (LONG)RTL_NUMBER_OF(KdbEnterConditions) ||
1016             ExceptionNr == 1 || ExceptionNr == 8 || /* Do not allow changing of the debug */
1017             ExceptionNr == 9 || ExceptionNr == 15)  /* trap or reserved exceptions */
1018         {
1019             return FALSE;
1020         }
1021 
1022         KdbEnterConditions[ExceptionNr][FirstChance ? 0 : 1] = Condition;
1023     }
1024 
1025     return TRUE;
1026 }
1027 
1028 /*!\brief Switches to another thread context
1029  *
1030  * \param ThreadId  Id of the thread to switch to.
1031  *
1032  * \retval TRUE   Success.
1033  * \retval FALSE  Failure (i.e. invalid thread id)
1034  */
1035 BOOLEAN
1036 KdbpAttachToThread(
1037     PVOID ThreadId)
1038 {
1039     PETHREAD Thread = NULL;
1040     PEPROCESS Process;
1041 
1042     /* Get a pointer to the thread */
1043     if (!NT_SUCCESS(PsLookupThreadByThreadId(ThreadId, &Thread)))
1044     {
1045         KdbpPrint("Invalid thread id: 0x%08x\n", (ULONG_PTR)ThreadId);
1046         return FALSE;
1047     }
1048     Process = Thread->ThreadsProcess;
1049 
1050     if (KeIsExecutingDpc() && Process != KdbCurrentProcess)
1051     {
1052         KdbpPrint("Cannot attach to thread within another process while executing a DPC.\n");
1053         ObDereferenceObject(Thread);
1054         return FALSE;
1055     }
1056 
1057     /* Save the current thread's context (if we previously attached to a thread) */
1058     if (KdbCurrentThread != KdbOriginalThread)
1059     {
1060         ASSERT(KdbCurrentTrapFrame == &KdbThreadTrapFrame);
1061         /* Actually, we can't save the context, there's no guarantee that there was a trap frame */
1062     }
1063     else
1064     {
1065         ASSERT(KdbCurrentTrapFrame == &KdbTrapFrame);
1066     }
1067 
1068     /* Switch to the thread's context */
1069     if (Thread != KdbOriginalThread)
1070     {
1071         /* The thread we're attaching to isn't the thread on which we entered
1072          * kdb and so the thread we're attaching to is not running. There
1073          * is no guarantee that it actually has a trap frame. So we have to
1074          * peek directly at the registers which were saved on the stack when the
1075          * thread was preempted in the scheduler */
1076         KdbpKdbTrapFrameFromKernelStack(Thread->Tcb.KernelStack,
1077                                         &KdbThreadTrapFrame);
1078         KdbCurrentTrapFrame = &KdbThreadTrapFrame;
1079     }
1080     else /* Switching back to original thread */
1081     {
1082         KdbCurrentTrapFrame = &KdbTrapFrame;
1083     }
1084     KdbCurrentThread = Thread;
1085 
1086     /* Attach to the thread's process */
1087     ASSERT(KdbCurrentProcess == PsGetCurrentProcess());
1088     if (KdbCurrentProcess != Process)
1089     {
1090         if (KdbCurrentProcess != KdbOriginalProcess) /* detach from previously attached process */
1091         {
1092             KeUnstackDetachProcess(&KdbApcState);
1093         }
1094 
1095         if (KdbOriginalProcess != Process)
1096         {
1097             KeStackAttachProcess(&Process->Pcb, &KdbApcState);
1098         }
1099 
1100         KdbCurrentProcess = Process;
1101     }
1102 
1103     ObDereferenceObject(Thread);
1104     return TRUE;
1105 }
1106 
1107 /*!\brief Switches to another process/thread context
1108  *
1109  * This function switches to the first thread in the specified process.
1110  *
1111  * \param ProcessId  Id of the process to switch to.
1112  *
1113  * \retval TRUE   Success.
1114  * \retval FALSE  Failure (i.e. invalid process id)
1115  */
1116 BOOLEAN
1117 KdbpAttachToProcess(
1118     PVOID ProcessId)
1119 {
1120     PEPROCESS Process = NULL;
1121     PETHREAD Thread;
1122     PLIST_ENTRY Entry;
1123 
1124     /* Get a pointer to the process */
1125     if (!NT_SUCCESS(PsLookupProcessByProcessId(ProcessId, &Process)))
1126     {
1127         KdbpPrint("Invalid process id: 0x%08x\n", (ULONG_PTR)ProcessId);
1128         return FALSE;
1129     }
1130 
1131     Entry = Process->ThreadListHead.Flink;
1132     ObDereferenceObject(Process);
1133     if (Entry == &KdbCurrentProcess->ThreadListHead)
1134     {
1135         KdbpPrint("No threads in process 0x%p, cannot attach to process!\n", ProcessId);
1136         return FALSE;
1137     }
1138 
1139     Thread = CONTAINING_RECORD(Entry, ETHREAD, ThreadListEntry);
1140 
1141     return KdbpAttachToThread(Thread->Cid.UniqueThread);
1142 }
1143 
1144 /*!\brief Calls the main loop ...
1145  */
1146 static VOID
1147 KdbpCallMainLoop(VOID)
1148 {
1149     KdbpCliMainLoop(KdbEnteredOnSingleStep);
1150 }
1151 
1152 /*!\brief Internal function to enter KDB.
1153  *
1154  * Disables interrupts, releases display ownership, ...
1155  */
1156 static VOID
1157 KdbpInternalEnter(VOID)
1158 {
1159     PETHREAD Thread;
1160     PVOID SavedInitialStack, SavedStackBase, SavedKernelStack;
1161     ULONG SavedStackLimit;
1162 
1163     KbdDisableMouse();
1164 
1165     /* Take control of the display */
1166     if (KdpDebugMode.Screen)
1167         KdpScreenAcquire();
1168 
1169     /* Call the interface's main loop on a different stack */
1170     Thread = PsGetCurrentThread();
1171     SavedInitialStack = Thread->Tcb.InitialStack;
1172     SavedStackBase = Thread->Tcb.StackBase;
1173     SavedStackLimit = Thread->Tcb.StackLimit;
1174     SavedKernelStack = Thread->Tcb.KernelStack;
1175     Thread->Tcb.InitialStack = Thread->Tcb.StackBase = (char*)KdbStack + KDB_STACK_SIZE;
1176     Thread->Tcb.StackLimit = (ULONG_PTR)KdbStack;
1177     Thread->Tcb.KernelStack = (char*)KdbStack + KDB_STACK_SIZE;
1178 
1179     // KdbPrintf("Switching to KDB stack 0x%08x-0x%08x (Current Stack is 0x%08x)\n", Thread->Tcb.StackLimit, Thread->Tcb.StackBase, Esp);
1180 
1181     KdbpStackSwitchAndCall(KdbStack + KDB_STACK_SIZE - KDB_STACK_RESERVE, KdbpCallMainLoop);
1182 
1183     Thread->Tcb.InitialStack = SavedInitialStack;
1184     Thread->Tcb.StackBase = SavedStackBase;
1185     Thread->Tcb.StackLimit = SavedStackLimit;
1186     Thread->Tcb.KernelStack = SavedKernelStack;
1187 
1188     /* Release the display */
1189     if (KdpDebugMode.Screen)
1190         KdpScreenRelease();
1191 
1192     KbdEnableMouse();
1193 }
1194 
1195 static ULONG
1196 KdbpGetExceptionNumberFromStatus(
1197     IN NTSTATUS ExceptionCode)
1198 {
1199     ULONG Ret;
1200 
1201     switch (ExceptionCode)
1202     {
1203         case STATUS_INTEGER_DIVIDE_BY_ZERO:
1204             Ret = 0;
1205             break;
1206         case STATUS_SINGLE_STEP:
1207             Ret = 1;
1208             break;
1209         case STATUS_BREAKPOINT:
1210             Ret = 3;
1211             break;
1212         case STATUS_INTEGER_OVERFLOW:
1213             Ret = 4;
1214             break;
1215         case STATUS_ARRAY_BOUNDS_EXCEEDED:
1216             Ret = 5;
1217             break;
1218         case STATUS_ILLEGAL_INSTRUCTION:
1219             Ret = 6;
1220             break;
1221         case STATUS_FLOAT_INVALID_OPERATION:
1222             Ret = 7;
1223             break;
1224         case STATUS_STACK_OVERFLOW:
1225             Ret = 12;
1226             break;
1227         case STATUS_ACCESS_VIOLATION:
1228             Ret = 14;
1229             break;
1230         case STATUS_DATATYPE_MISALIGNMENT:
1231             Ret = 17;
1232             break;
1233         case STATUS_FLOAT_MULTIPLE_TRAPS:
1234             Ret = 18;
1235             break;
1236         case STATUS_ASSERTION_FAILURE:
1237             Ret = 20;
1238             break;
1239 
1240         default:
1241             Ret = RTL_NUMBER_OF(KdbEnterConditions) - 1;
1242             break;
1243     }
1244 
1245     return Ret;
1246 }
1247 
1248 /*!\brief KDB Exception filter
1249  *
1250  * Called by the exception dispatcher.
1251  *
1252  * \param ExceptionRecord  Unused.
1253  * \param PreviousMode     UserMode if the exception was raised from umode, otherwise KernelMode.
1254  * \param Context          Context, IN/OUT parameter.
1255  * \param TrapFrame        Exception TrapFrame.
1256  * \param FirstChance      TRUE when called before exception frames were serached,
1257  *                         FALSE for the second call.
1258  *
1259  * \returns KD_CONTINUE_TYPE
1260  */
1261 KD_CONTINUE_TYPE
1262 KdbEnterDebuggerException(
1263     IN PEXCEPTION_RECORD64 ExceptionRecord,
1264     IN KPROCESSOR_MODE PreviousMode,
1265     IN PCONTEXT Context,
1266     IN BOOLEAN FirstChance)
1267 {
1268     KDB_ENTER_CONDITION EnterCondition;
1269     KD_CONTINUE_TYPE ContinueType = kdHandleException;
1270     PKDB_BREAKPOINT BreakPoint;
1271     ULONG ExpNr;
1272     ULONGLONG ull;
1273     BOOLEAN Resume = FALSE;
1274     BOOLEAN EnterConditionMet = TRUE;
1275     ULONG OldEflags;
1276     KIRQL OldIrql;
1277     NTSTATUS ExceptionCode;
1278 
1279     ExceptionCode = (ExceptionRecord ? ExceptionRecord->ExceptionCode : STATUS_BREAKPOINT);
1280 
1281     KdbCurrentProcess = PsGetCurrentProcess();
1282 
1283     /* Set continue type to kdContinue for single steps and breakpoints */
1284     if (ExceptionCode == STATUS_SINGLE_STEP ||
1285         ExceptionCode == STATUS_BREAKPOINT ||
1286         ExceptionCode == STATUS_ASSERTION_FAILURE)
1287     {
1288         ContinueType = kdContinue;
1289     }
1290 
1291     /* Check if we should handle the exception. */
1292     /* FIXME - won't get all exceptions here :( */
1293     ExpNr = KdbpGetExceptionNumberFromStatus(ExceptionCode);
1294     EnterCondition = KdbEnterConditions[ExpNr][FirstChance ? 0 : 1];
1295     if (EnterCondition == KdbDoNotEnter ||
1296         (EnterCondition == KdbEnterFromUmode && PreviousMode == KernelMode) ||
1297         (EnterCondition == KdbEnterFromKmode && PreviousMode != KernelMode))
1298     {
1299         EnterConditionMet = FALSE;
1300     }
1301 
1302     /* If we stopped on one of our breakpoints then let the user know */
1303     KdbLastBreakPointNr = -1;
1304     KdbEnteredOnSingleStep = FALSE;
1305 
1306     if (FirstChance && (ExceptionCode == STATUS_SINGLE_STEP || ExceptionCode == STATUS_BREAKPOINT) &&
1307         (KdbLastBreakPointNr = KdbpIsBreakPointOurs(ExceptionCode, Context)) >= 0)
1308     {
1309         BreakPoint = KdbBreakPoints + KdbLastBreakPointNr;
1310 
1311         if (ExceptionCode == STATUS_BREAKPOINT)
1312         {
1313             /* ... and restore the original instruction */
1314             if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess, BreakPoint->Address,
1315                                                      BreakPoint->Data.SavedInstruction, NULL)))
1316             {
1317                 KdbPuts("Couldn't restore original instruction after INT3! Cannot continue execution.\n");
1318                 KeBugCheck(0); // FIXME: Proper bugcode!
1319             }
1320 
1321             /* Also since we are past the int3 now, decrement EIP in the
1322                TrapFrame. This is only needed because KDBG insists on working
1323                with the TrapFrame instead of with the Context, as it is supposed
1324                to do. The context has already EIP point to the int3, since
1325                KiDispatchException accounts for that. Whatever we do here with
1326                the TrapFrame does not matter anyway, since KiDispatchException
1327                will overwrite it with the values from the Context! */
1328             KeSetContextPc(Context, KeGetContextPc(Context) - 1);
1329         }
1330 
1331         if ((BreakPoint->Type == KdbBreakPointHardware) &&
1332             (BreakPoint->Data.Hw.AccessType == KdbAccessExec))
1333         {
1334             Resume = TRUE; /* Set the resume flag when continuing execution */
1335         }
1336 
1337         /*
1338          * When a temporary breakpoint is hit we have to make sure that we are
1339          * in the same context in which it was set, otherwise it could happen
1340          * that another process/thread hits it before and it gets deleted.
1341          */
1342         else if (BreakPoint->Type == KdbBreakPointTemporary &&
1343                  BreakPoint->Process == KdbCurrentProcess)
1344         {
1345             ASSERT((Context->EFlags & EFLAGS_TF) == 0);
1346 
1347             /* Delete the temporary breakpoint which was used to step over or into the instruction */
1348             KdbpDeleteBreakPoint(-1, BreakPoint);
1349 
1350             if (--KdbNumSingleSteps > 0)
1351             {
1352                 if ((KdbSingleStepOver && !KdbpStepOverInstruction(KeGetContextPc(Context))) ||
1353                     (!KdbSingleStepOver && !KdbpStepIntoInstruction(KeGetContextPc(Context))))
1354                 {
1355                     Context->EFlags |= EFLAGS_TF;
1356                 }
1357 
1358                 goto continue_execution; /* return */
1359             }
1360 
1361             KdbEnteredOnSingleStep = TRUE;
1362         }
1363 
1364         /*
1365          * If we hit a breakpoint set by the debugger we set the single step flag,
1366          * ignore the next single step and reenable the breakpoint.
1367          */
1368         else if (BreakPoint->Type == KdbBreakPointSoftware ||
1369                  BreakPoint->Type == KdbBreakPointTemporary)
1370         {
1371             ASSERT(ExceptionCode == STATUS_BREAKPOINT);
1372             Context->EFlags |= EFLAGS_TF;
1373             KdbBreakPointToReenable = BreakPoint;
1374         }
1375 
1376         /* Make sure that the breakpoint should be triggered in this context */
1377         if (!BreakPoint->Global && BreakPoint->Process != KdbCurrentProcess)
1378         {
1379             goto continue_execution; /* return */
1380         }
1381 
1382         /* Check if the condition for the breakpoint is met. */
1383         if (BreakPoint->Condition)
1384         {
1385             /* Setup the KDB trap frame */
1386             KdbTrapFrame = *Context;
1387 
1388             ull = 0;
1389             if (!KdbpRpnEvaluateParsedExpression(BreakPoint->Condition, &KdbTrapFrame, &ull, NULL, NULL))
1390             {
1391                 /* FIXME: Print warning? */
1392             }
1393             else if (ull == 0) /* condition is not met */
1394             {
1395                 goto continue_execution; /* return */
1396             }
1397         }
1398 
1399         if (BreakPoint->Type == KdbBreakPointSoftware)
1400         {
1401             KdbPrintf("\nEntered debugger on breakpoint #%d: EXEC 0x%04x:0x%p\n",
1402                       KdbLastBreakPointNr, Context->SegCs & 0xffff, KeGetContextPc(Context));
1403         }
1404         else if (BreakPoint->Type == KdbBreakPointHardware)
1405         {
1406             KdbPrintf("\nEntered debugger on breakpoint #%d: %s 0x%08x\n",
1407                       KdbLastBreakPointNr,
1408                       (BreakPoint->Data.Hw.AccessType == KdbAccessRead) ? "READ" :
1409                       ((BreakPoint->Data.Hw.AccessType == KdbAccessWrite) ? "WRITE" :
1410                       ((BreakPoint->Data.Hw.AccessType == KdbAccessReadWrite) ? "RDWR" : "EXEC")),
1411                       BreakPoint->Address);
1412         }
1413     }
1414     else if (ExceptionCode == STATUS_SINGLE_STEP)
1415     {
1416         /* Silently ignore a debugger initiated single step. */
1417         if ((Context->Dr6 & 0xf) == 0 && KdbBreakPointToReenable)
1418         {
1419             /* FIXME: Make sure that the breakpoint was really hit (check bp->Address vs. tf->Eip) */
1420             BreakPoint = KdbBreakPointToReenable;
1421             KdbBreakPointToReenable = NULL;
1422             ASSERT(BreakPoint->Type == KdbBreakPointSoftware ||
1423                    BreakPoint->Type == KdbBreakPointTemporary);
1424 
1425             /*
1426              * Reenable the breakpoint we disabled to execute the breakpointed
1427              * instruction.
1428              */
1429             if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess, BreakPoint->Address, 0xCC,
1430                                                      &BreakPoint->Data.SavedInstruction)))
1431             {
1432                 KdbPrintf("Warning: Couldn't reenable breakpoint %d\n",
1433                           BreakPoint - KdbBreakPoints);
1434             }
1435 
1436             /* Unset TF if we are no longer single stepping. */
1437             if (KdbNumSingleSteps == 0)
1438                 Context->EFlags &= ~EFLAGS_TF;
1439 
1440             if (!KdbpEvenThoughWeHaveABreakPointToReenableWeAlsoHaveARealSingleStep)
1441             {
1442                 goto continue_execution; /* return */
1443             }
1444         }
1445 
1446         /* Quoth the raven, 'Nevermore!' */
1447         KdbpEvenThoughWeHaveABreakPointToReenableWeAlsoHaveARealSingleStep = FALSE;
1448 
1449         /* Check if we expect a single step */
1450         if ((Context->Dr6 & 0xf) == 0 && KdbNumSingleSteps > 0)
1451         {
1452             /*ASSERT((Context->Eflags & EFLAGS_TF) != 0);*/
1453             if (--KdbNumSingleSteps > 0)
1454             {
1455                 if ((KdbSingleStepOver && KdbpStepOverInstruction(KeGetContextPc(Context))) ||
1456                     (!KdbSingleStepOver && KdbpStepIntoInstruction(KeGetContextPc(Context))))
1457                 {
1458                     Context->EFlags &= ~EFLAGS_TF;
1459                 }
1460                 else
1461                 {
1462                     Context->EFlags |= EFLAGS_TF;
1463                 }
1464 
1465                 goto continue_execution; /* return */
1466             }
1467             else
1468             {
1469                 Context->EFlags &= ~EFLAGS_TF;
1470                 KdbEnteredOnSingleStep = TRUE;
1471             }
1472         }
1473         else
1474         {
1475             if (!EnterConditionMet)
1476             {
1477                 return kdHandleException;
1478             }
1479 
1480             KdbPuts("\nEntered debugger on unexpected debug trap!\n");
1481         }
1482     }
1483     else if (ExceptionCode == STATUS_BREAKPOINT)
1484     {
1485         if (KdbInitFileBuffer)
1486         {
1487             KdbpCliInterpretInitFile();
1488             EnterConditionMet = FALSE;
1489         }
1490         if (!EnterConditionMet)
1491         {
1492             return kdHandleException;
1493         }
1494 
1495         KdbPrintf("\nEntered debugger on embedded INT3 at 0x%04x:0x%p.\n",
1496                   Context->SegCs & 0xffff, KeGetContextPc(Context));
1497     }
1498     else
1499     {
1500         const CHAR *ExceptionString = (ExpNr < RTL_NUMBER_OF(ExceptionNrToString)) ?
1501                                       ExceptionNrToString[ExpNr] :
1502                                       "Unknown/User defined exception";
1503 
1504         if (!EnterConditionMet)
1505         {
1506             return ContinueType;
1507         }
1508 
1509         KdbPrintf("\nEntered debugger on %s-chance exception (Exception Code: 0x%x) (%s)\n",
1510                   FirstChance ? "first" : "last", ExceptionCode, ExceptionString);
1511 
1512         if (ExceptionCode == STATUS_ACCESS_VIOLATION &&
1513             ExceptionRecord && ExceptionRecord->NumberParameters != 0)
1514         {
1515             ULONG_PTR TrapCr2 = __readcr2();
1516             KdbPrintf("Memory at 0x%p could not be accessed\n", TrapCr2);
1517         }
1518     }
1519 
1520     /* Once we enter the debugger we do not expect any more single steps to happen */
1521     KdbNumSingleSteps = 0;
1522 
1523     /* Update the current process pointer */
1524     KdbCurrentProcess = KdbOriginalProcess = PsGetCurrentProcess();
1525     KdbCurrentThread = KdbOriginalThread = PsGetCurrentThread();
1526     KdbCurrentTrapFrame = &KdbTrapFrame;
1527 
1528     /* Setup the KDB trap frame */
1529     KdbTrapFrame = *Context;
1530 
1531     /* Enter critical section */
1532     OldEflags = __readeflags();
1533     _disable();
1534 
1535     /* HACK: Save the current IRQL and pretend we are at dispatch level */
1536     OldIrql = KeGetCurrentIrql();
1537     if (OldIrql > DISPATCH_LEVEL)
1538         KeLowerIrql(DISPATCH_LEVEL);
1539 
1540     /* Exception inside the debugger? Game over. */
1541     if (InterlockedIncrement(&KdbEntryCount) > 1)
1542     {
1543         __writeeflags(OldEflags);
1544         return kdHandleException;
1545     }
1546 
1547     /* Call the main loop */
1548     KdbpInternalEnter();
1549 
1550     /* Check if we should single step */
1551     if (KdbNumSingleSteps > 0)
1552     {
1553         /* Variable explains itself! */
1554         KdbpEvenThoughWeHaveABreakPointToReenableWeAlsoHaveARealSingleStep = TRUE;
1555 
1556         if ((KdbSingleStepOver && KdbpStepOverInstruction(KeGetContextPc(KdbCurrentTrapFrame))) ||
1557             (!KdbSingleStepOver && KdbpStepIntoInstruction(KeGetContextPc(KdbCurrentTrapFrame))))
1558         {
1559             ASSERT((KdbCurrentTrapFrame->EFlags & EFLAGS_TF) == 0);
1560             /*KdbCurrentTrapFrame->EFlags &= ~EFLAGS_TF;*/
1561         }
1562         else
1563         {
1564             KdbTrapFrame.EFlags |= EFLAGS_TF;
1565         }
1566     }
1567 
1568     /* We can't update the current thread's trapframe 'cause it might not have one */
1569 
1570     /* Detach from attached process */
1571     if (KdbCurrentProcess != KdbOriginalProcess)
1572     {
1573         KeUnstackDetachProcess(&KdbApcState);
1574     }
1575 
1576     /* Update the exception Context */
1577     *Context = KdbTrapFrame;
1578 
1579     /* Decrement the entry count */
1580     InterlockedDecrement(&KdbEntryCount);
1581 
1582     /* HACK: Raise back to old IRQL */
1583     if (OldIrql > DISPATCH_LEVEL)
1584         KeRaiseIrql(OldIrql, &OldIrql);
1585 
1586     /* Leave critical section */
1587     __writeeflags(OldEflags);
1588 
1589     /* Check if user requested a bugcheck */
1590     if (KdbpBugCheckRequested)
1591     {
1592         /* Clear the flag and bugcheck the system */
1593         KdbpBugCheckRequested = FALSE;
1594         KeBugCheck(MANUALLY_INITIATED_CRASH);
1595     }
1596 
1597 continue_execution:
1598     /* Clear debug status */
1599     if (ExceptionCode == STATUS_BREAKPOINT) /* FIXME: Why clear DR6 on INT3? */
1600     {
1601         /* Set the RF flag so we don't trigger the same breakpoint again. */
1602         if (Resume)
1603         {
1604             Context->EFlags |= EFLAGS_RF;
1605         }
1606 
1607         /* Clear dr6 status flags. */
1608         Context->Dr6 &= ~0x0000e00f;
1609 
1610         if (!(KdbEnteredOnSingleStep && KdbSingleStepOver))
1611         {
1612             /* Skip the current instruction */
1613             KeSetContextPc(Context, KeGetContextPc(Context) + KD_BREAKPOINT_SIZE);
1614         }
1615     }
1616 
1617     return ContinueType;
1618 }
1619 
1620 VOID
1621 KdbpGetCommandLineSettings(
1622     _In_ PCSTR p1)
1623 {
1624 #define CONST_STR_LEN(x) (sizeof(x)/sizeof(x[0]) - 1)
1625 
1626     while (p1 && *p1)
1627     {
1628         /* Skip leading whitespace */
1629         while (*p1 == ' ') ++p1;
1630 
1631         if (!_strnicmp(p1, "FIRSTCHANCE", CONST_STR_LEN("FIRSTCHANCE")))
1632         {
1633             p1 += CONST_STR_LEN("FIRSTCHANCE");
1634             KdbpSetEnterCondition(-1, TRUE, KdbEnterAlways);
1635         }
1636 
1637         /* Move on to the next option */
1638         p1 = strchr(p1, ' ');
1639     }
1640 }
1641 
1642 NTSTATUS
1643 KdbpSafeReadMemory(
1644     OUT PVOID Dest,
1645     IN PVOID Src,
1646     IN ULONG Bytes)
1647 {
1648     return KdpCopyMemoryChunks((ULONG64)(ULONG_PTR)Src,
1649                                Dest,
1650                                Bytes,
1651                                0,
1652                                MMDBG_COPY_UNSAFE,
1653                                NULL);
1654 }
1655 
1656 NTSTATUS
1657 KdbpSafeWriteMemory(
1658     OUT PVOID Dest,
1659     IN PVOID Src,
1660     IN ULONG Bytes)
1661 {
1662     return KdpCopyMemoryChunks((ULONG64)(ULONG_PTR)Dest,
1663                                Src,
1664                                Bytes,
1665                                0,
1666                                MMDBG_COPY_UNSAFE | MMDBG_COPY_WRITE,
1667                                NULL);
1668 }
1669