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