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