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