xref: /reactos/ntoskrnl/kdbg/kdb.c (revision fb5d5ecd)
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     if (KdpDebugMode.Screen &&
1222         InbvIsBootDriverInstalled() &&
1223         !InbvCheckDisplayOwnership())
1224     {
1225         /* Acquire ownership and reset the display */
1226         InbvAcquireDisplayOwnership();
1227         InbvResetDisplay();
1228 
1229         /* Display debugger prompt */
1230         InbvSolidColorFill(0, 0, 639, 479, 0);
1231         InbvSetTextColor(15);
1232         InbvInstallDisplayStringFilter(NULL);
1233         InbvEnableDisplayString(TRUE);
1234         InbvSetScrollRegion(0, 0, 639, 479);
1235     }
1236 
1237     /* Call the interface's main loop on a different stack */
1238     Thread = PsGetCurrentThread();
1239     SavedInitialStack = Thread->Tcb.InitialStack;
1240     SavedStackBase = Thread->Tcb.StackBase;
1241     SavedStackLimit = Thread->Tcb.StackLimit;
1242     SavedKernelStack = Thread->Tcb.KernelStack;
1243     Thread->Tcb.InitialStack = Thread->Tcb.StackBase = (char*)KdbStack + KDB_STACK_SIZE;
1244     Thread->Tcb.StackLimit = (ULONG_PTR)KdbStack;
1245     Thread->Tcb.KernelStack = (char*)KdbStack + KDB_STACK_SIZE;
1246 
1247     /*KdbpPrint("Switching to KDB stack 0x%08x-0x%08x (Current Stack is 0x%08x)\n", Thread->Tcb.StackLimit, Thread->Tcb.StackBase, Esp);*/
1248 
1249     KdbpStackSwitchAndCall(KdbStack + KDB_STACK_SIZE - sizeof(ULONG), KdbpCallMainLoop);
1250 
1251     Thread->Tcb.InitialStack = SavedInitialStack;
1252     Thread->Tcb.StackBase = SavedStackBase;
1253     Thread->Tcb.StackLimit = SavedStackLimit;
1254     Thread->Tcb.KernelStack = SavedKernelStack;
1255     KbdEnableMouse();
1256 }
1257 
1258 static ULONG
1259 KdbpGetExceptionNumberFromStatus(
1260     IN NTSTATUS ExceptionCode)
1261 {
1262     ULONG Ret;
1263 
1264     switch (ExceptionCode)
1265     {
1266         case STATUS_INTEGER_DIVIDE_BY_ZERO:
1267             Ret = 0;
1268             break;
1269         case STATUS_SINGLE_STEP:
1270             Ret = 1;
1271             break;
1272         case STATUS_BREAKPOINT:
1273             Ret = 3;
1274             break;
1275         case STATUS_INTEGER_OVERFLOW:
1276             Ret = 4;
1277             break;
1278         case STATUS_ARRAY_BOUNDS_EXCEEDED:
1279             Ret = 5;
1280             break;
1281         case STATUS_ILLEGAL_INSTRUCTION:
1282             Ret = 6;
1283             break;
1284         case STATUS_FLOAT_INVALID_OPERATION:
1285             Ret = 7;
1286             break;
1287         case STATUS_STACK_OVERFLOW:
1288             Ret = 12;
1289             break;
1290         case STATUS_ACCESS_VIOLATION:
1291             Ret = 14;
1292             break;
1293         case STATUS_DATATYPE_MISALIGNMENT:
1294             Ret = 17;
1295             break;
1296         case STATUS_FLOAT_MULTIPLE_TRAPS:
1297             Ret = 18;
1298             break;
1299         case STATUS_ASSERTION_FAILURE:
1300             Ret = 20;
1301             break;
1302 
1303         default:
1304             Ret = RTL_NUMBER_OF(KdbEnterConditions) - 1;
1305             break;
1306     }
1307 
1308     return Ret;
1309 }
1310 
1311 /*!\brief KDB Exception filter
1312  *
1313  * Called by the exception dispatcher.
1314  *
1315  * \param ExceptionRecord  Unused.
1316  * \param PreviousMode     UserMode if the exception was raised from umode, otherwise KernelMode.
1317  * \param Context          Context, IN/OUT parameter.
1318  * \param TrapFrame        Exception TrapFrame.
1319  * \param FirstChance      TRUE when called before exception frames were serached,
1320  *                         FALSE for the second call.
1321  *
1322  * \returns KD_CONTINUE_TYPE
1323  */
1324 KD_CONTINUE_TYPE
1325 KdbEnterDebuggerException(
1326     IN PEXCEPTION_RECORD ExceptionRecord  OPTIONAL,
1327     IN KPROCESSOR_MODE PreviousMode,
1328     IN PCONTEXT Context,
1329     IN OUT PKTRAP_FRAME TrapFrame,
1330     IN BOOLEAN FirstChance)
1331 {
1332     KDB_ENTER_CONDITION EnterCondition;
1333     KD_CONTINUE_TYPE ContinueType = kdHandleException;
1334     PKDB_BREAKPOINT BreakPoint;
1335     ULONG ExpNr;
1336     ULONGLONG ull;
1337     BOOLEAN Resume = FALSE;
1338     BOOLEAN EnterConditionMet = TRUE;
1339     ULONG OldEflags;
1340     KIRQL OldIrql;
1341     NTSTATUS ExceptionCode;
1342 
1343     ExceptionCode = (ExceptionRecord ? ExceptionRecord->ExceptionCode : STATUS_BREAKPOINT);
1344 
1345     KdbCurrentProcess = PsGetCurrentProcess();
1346 
1347     /* Set continue type to kdContinue for single steps and breakpoints */
1348     if (ExceptionCode == STATUS_SINGLE_STEP ||
1349         ExceptionCode == STATUS_BREAKPOINT ||
1350         ExceptionCode == STATUS_ASSERTION_FAILURE)
1351     {
1352         ContinueType = kdContinue;
1353     }
1354 
1355     /* Check if we should handle the exception. */
1356     /* FIXME - won't get all exceptions here :( */
1357     ExpNr = KdbpGetExceptionNumberFromStatus(ExceptionCode);
1358     EnterCondition = KdbEnterConditions[ExpNr][FirstChance ? 0 : 1];
1359     if (EnterCondition == KdbDoNotEnter ||
1360         (EnterCondition == KdbEnterFromUmode && PreviousMode == KernelMode) ||
1361         (EnterCondition == KdbEnterFromKmode && PreviousMode != KernelMode))
1362     {
1363         EnterConditionMet = FALSE;
1364     }
1365 
1366     /* If we stopped on one of our breakpoints then let the user know. */
1367     KdbLastBreakPointNr = -1;
1368     KdbEnteredOnSingleStep = FALSE;
1369 
1370     if (FirstChance && (ExceptionCode == STATUS_SINGLE_STEP || ExceptionCode == STATUS_BREAKPOINT) &&
1371         (KdbLastBreakPointNr = KdbpIsBreakPointOurs(ExceptionCode, TrapFrame)) >= 0)
1372     {
1373         BreakPoint = KdbBreakPoints + KdbLastBreakPointNr;
1374 
1375         if (ExceptionCode == STATUS_BREAKPOINT)
1376         {
1377             /* ... and restore the original instruction. */
1378             if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess, BreakPoint->Address,
1379                                                      BreakPoint->Data.SavedInstruction, NULL)))
1380             {
1381                 KdbpPrint("Couldn't restore original instruction after INT3! Cannot continue execution.\n");
1382                 KeBugCheck(0); // FIXME: Proper bugcode!
1383             }
1384 
1385             /* Also since we are past the int3 now, decrement EIP in the
1386                TrapFrame. This is only needed because KDBG insists on working
1387                with the TrapFrame instead of with the Context, as it is supposed
1388                to do. The context has already EIP point to the int3, since
1389                KiDispatchException accounts for that. Whatever we do here with
1390                the TrapFrame does not matter anyway, since KiDispatchException
1391                will overwrite it with the values from the Context! */
1392             TrapFrame->Eip--;
1393         }
1394 
1395         if ((BreakPoint->Type == KdbBreakPointHardware) &&
1396             (BreakPoint->Data.Hw.AccessType == KdbAccessExec))
1397         {
1398             Resume = TRUE; /* Set the resume flag when continuing execution */
1399         }
1400 
1401         /*
1402          * When a temporary breakpoint is hit we have to make sure that we are
1403          * in the same context in which it was set, otherwise it could happen
1404          * that another process/thread hits it before and it gets deleted.
1405          */
1406         else if (BreakPoint->Type == KdbBreakPointTemporary &&
1407                  BreakPoint->Process == KdbCurrentProcess)
1408         {
1409             ASSERT((TrapFrame->EFlags & EFLAGS_TF) == 0);
1410 
1411             /* Delete the temporary breakpoint which was used to step over or into the instruction. */
1412             KdbpDeleteBreakPoint(-1, BreakPoint);
1413 
1414             if (--KdbNumSingleSteps > 0)
1415             {
1416                 if ((KdbSingleStepOver && !KdbpStepOverInstruction(TrapFrame->Eip)) ||
1417                     (!KdbSingleStepOver && !KdbpStepIntoInstruction(TrapFrame->Eip)))
1418                 {
1419                     Context->EFlags |= EFLAGS_TF;
1420                 }
1421 
1422                 goto continue_execution; /* return */
1423             }
1424 
1425             KdbEnteredOnSingleStep = TRUE;
1426         }
1427 
1428         /*
1429          * If we hit a breakpoint set by the debugger we set the single step flag,
1430          * ignore the next single step and reenable the breakpoint.
1431          */
1432         else if (BreakPoint->Type == KdbBreakPointSoftware ||
1433                  BreakPoint->Type == KdbBreakPointTemporary)
1434         {
1435             ASSERT(ExceptionCode == STATUS_BREAKPOINT);
1436             Context->EFlags |= EFLAGS_TF;
1437             KdbBreakPointToReenable = BreakPoint;
1438         }
1439 
1440         /* Make sure that the breakpoint should be triggered in this context */
1441         if (!BreakPoint->Global && BreakPoint->Process != KdbCurrentProcess)
1442         {
1443             goto continue_execution; /* return */
1444         }
1445 
1446         /* Check if the condition for the breakpoint is met. */
1447         if (BreakPoint->Condition)
1448         {
1449             /* Setup the KDB trap frame */
1450             KdbpTrapFrameToKdbTrapFrame(TrapFrame, &KdbTrapFrame);
1451 
1452             ull = 0;
1453             if (!KdbpRpnEvaluateParsedExpression(BreakPoint->Condition, &KdbTrapFrame, &ull, NULL, NULL))
1454             {
1455                 /* FIXME: Print warning? */
1456             }
1457             else if (ull == 0) /* condition is not met */
1458             {
1459                 goto continue_execution; /* return */
1460             }
1461         }
1462 
1463         if (BreakPoint->Type == KdbBreakPointSoftware)
1464         {
1465             KdbpPrint("\nEntered debugger on breakpoint #%d: EXEC 0x%04x:0x%08x\n",
1466                       KdbLastBreakPointNr, TrapFrame->SegCs & 0xffff, TrapFrame->Eip);
1467         }
1468         else if (BreakPoint->Type == KdbBreakPointHardware)
1469         {
1470             KdbpPrint("\nEntered debugger on breakpoint #%d: %s 0x%08x\n",
1471                       KdbLastBreakPointNr,
1472                      (BreakPoint->Data.Hw.AccessType == KdbAccessRead) ? "READ" :
1473                      ((BreakPoint->Data.Hw.AccessType == KdbAccessWrite) ? "WRITE" :
1474                      ((BreakPoint->Data.Hw.AccessType == KdbAccessReadWrite) ? "RDWR" : "EXEC")),
1475                      BreakPoint->Address);
1476         }
1477     }
1478     else if (ExceptionCode == STATUS_SINGLE_STEP)
1479     {
1480         /* Silently ignore a debugger initiated single step. */
1481         if ((TrapFrame->Dr6 & 0xf) == 0 && KdbBreakPointToReenable)
1482         {
1483             /* FIXME: Make sure that the breakpoint was really hit (check bp->Address vs. tf->Eip) */
1484             BreakPoint = KdbBreakPointToReenable;
1485             KdbBreakPointToReenable = NULL;
1486             ASSERT(BreakPoint->Type == KdbBreakPointSoftware ||
1487                    BreakPoint->Type == KdbBreakPointTemporary);
1488 
1489             /*
1490              * Reenable the breakpoint we disabled to execute the breakpointed
1491              * instruction.
1492              */
1493             if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess, BreakPoint->Address, 0xCC,
1494                                                      &BreakPoint->Data.SavedInstruction)))
1495             {
1496                 KdbpPrint("Warning: Couldn't reenable breakpoint %d\n",
1497                           BreakPoint - KdbBreakPoints);
1498             }
1499 
1500             /* Unset TF if we are no longer single stepping. */
1501             if (KdbNumSingleSteps == 0)
1502                 Context->EFlags &= ~EFLAGS_TF;
1503 
1504             if (!KdbpEvenThoughWeHaveABreakPointToReenableWeAlsoHaveARealSingleStep)
1505             {
1506                 goto continue_execution; /* return */
1507             }
1508         }
1509 
1510         /* Quoth the raven, 'Nevermore!' */
1511         KdbpEvenThoughWeHaveABreakPointToReenableWeAlsoHaveARealSingleStep = FALSE;
1512 
1513         /* Check if we expect a single step */
1514         if ((TrapFrame->Dr6 & 0xf) == 0 && KdbNumSingleSteps > 0)
1515         {
1516             /*ASSERT((Context->Eflags & EFLAGS_TF) != 0);*/
1517             if (--KdbNumSingleSteps > 0)
1518             {
1519                 if ((KdbSingleStepOver && KdbpStepOverInstruction(TrapFrame->Eip)) ||
1520                     (!KdbSingleStepOver && KdbpStepIntoInstruction(TrapFrame->Eip)))
1521                 {
1522                     Context->EFlags &= ~EFLAGS_TF;
1523                 }
1524                 else
1525                 {
1526                     Context->EFlags |= EFLAGS_TF;
1527                 }
1528 
1529                 goto continue_execution; /* return */
1530             }
1531             else
1532             {
1533                 Context->EFlags &= ~EFLAGS_TF;
1534                 KdbEnteredOnSingleStep = TRUE;
1535             }
1536         }
1537         else
1538         {
1539             if (!EnterConditionMet)
1540             {
1541                 return kdHandleException;
1542             }
1543 
1544             KdbpPrint("\nEntered debugger on unexpected debug trap!\n");
1545         }
1546     }
1547     else if (ExceptionCode == STATUS_BREAKPOINT)
1548     {
1549         if (KdbInitFileBuffer)
1550         {
1551             KdbpCliInterpretInitFile();
1552             EnterConditionMet = FALSE;
1553         }
1554         if (!EnterConditionMet)
1555         {
1556             return kdHandleException;
1557         }
1558 
1559         KdbpPrint("\nEntered debugger on embedded INT3 at 0x%04x:0x%08x.\n",
1560                   TrapFrame->SegCs & 0xffff, TrapFrame->Eip - 1);
1561     }
1562     else
1563     {
1564         const CHAR *ExceptionString = (ExpNr < RTL_NUMBER_OF(ExceptionNrToString)) ?
1565                                       (ExceptionNrToString[ExpNr]) :
1566                                       ("Unknown/User defined exception");
1567 
1568         if (!EnterConditionMet)
1569         {
1570             return ContinueType;
1571         }
1572 
1573         KdbpPrint("\nEntered debugger on %s-chance exception (Exception Code: 0x%x) (%s)\n",
1574                   FirstChance ? "first" : "last", ExceptionCode, ExceptionString);
1575 
1576         if (ExceptionCode == STATUS_ACCESS_VIOLATION &&
1577             ExceptionRecord && ExceptionRecord->NumberParameters != 0)
1578         {
1579             /* FIXME: Add noexec memory stuff */
1580             ULONG_PTR TrapCr2;
1581             ULONG Err;
1582 
1583             TrapCr2 = __readcr2();
1584 
1585             Err = TrapFrame->ErrCode;
1586             KdbpPrint("Memory at 0x%p could not be %s: ", TrapCr2, (Err & (1 << 1)) ? "written" : "read");
1587 
1588             if ((Err & (1 << 0)) == 0)
1589             {
1590                 KdbpPrint("Page not present.\n");
1591             }
1592             else
1593             {
1594                 if ((Err & (1 << 3)) != 0)
1595                     KdbpPrint("Reserved bits in page directory set.\n");
1596                 else
1597                     KdbpPrint("Page protection violation.\n");
1598             }
1599         }
1600     }
1601 
1602     /* Once we enter the debugger we do not expect any more single steps to happen */
1603     KdbNumSingleSteps = 0;
1604 
1605     /* Update the current process pointer */
1606     KdbCurrentProcess = KdbOriginalProcess = PsGetCurrentProcess();
1607     KdbCurrentThread = KdbOriginalThread = PsGetCurrentThread();
1608     KdbCurrentTrapFrame = &KdbTrapFrame;
1609 
1610     /* Setup the KDB trap frame */
1611     KdbpTrapFrameToKdbTrapFrame(TrapFrame, &KdbTrapFrame);
1612 
1613     /* Enter critical section */
1614     OldEflags = __readeflags();
1615     _disable();
1616 
1617     /* HACK: Save the current IRQL and pretend we are at passive level,
1618      * although interrupts are off. Needed because KDBG calls pageable code. */
1619     OldIrql = KeGetCurrentIrql();
1620     KeLowerIrql(PASSIVE_LEVEL);
1621 
1622     /* Exception inside the debugger? Game over. */
1623     if (InterlockedIncrement(&KdbEntryCount) > 1)
1624     {
1625         __writeeflags(OldEflags);
1626         return kdHandleException;
1627     }
1628 
1629     /* Call the main loop. */
1630     KdbpInternalEnter();
1631 
1632     /* Check if we should single step */
1633     if (KdbNumSingleSteps > 0)
1634     {
1635         /* Variable explains itself! */
1636         KdbpEvenThoughWeHaveABreakPointToReenableWeAlsoHaveARealSingleStep = TRUE;
1637 
1638         if ((KdbSingleStepOver && KdbpStepOverInstruction(KdbCurrentTrapFrame->Tf.Eip)) ||
1639             (!KdbSingleStepOver && KdbpStepIntoInstruction(KdbCurrentTrapFrame->Tf.Eip)))
1640         {
1641             ASSERT((KdbCurrentTrapFrame->Tf.EFlags & EFLAGS_TF) == 0);
1642             /*KdbCurrentTrapFrame->Tf.EFlags &= ~EFLAGS_TF;*/
1643         }
1644         else
1645         {
1646             Context->EFlags |= EFLAGS_TF;
1647         }
1648     }
1649 
1650     /* We can't update the current thread's trapframe 'cause it might not have one */
1651 
1652     /* Detach from attached process */
1653     if (KdbCurrentProcess != KdbOriginalProcess)
1654     {
1655         KeUnstackDetachProcess(&KdbApcState);
1656     }
1657 
1658     /* Update the exception TrapFrame */
1659     KdbpKdbTrapFrameToTrapFrame(&KdbTrapFrame, TrapFrame);
1660 
1661     /* Decrement the entry count */
1662     InterlockedDecrement(&KdbEntryCount);
1663 
1664     /* HACK: Raise back to old IRQL */
1665     KeRaiseIrql(OldIrql, &OldIrql);
1666 
1667     /* Leave critical section */
1668     __writeeflags(OldEflags);
1669 
1670     /* Check if user requested a bugcheck */
1671     if (KdbpBugCheckRequested)
1672     {
1673         /* Clear the flag and bugcheck the system */
1674         KdbpBugCheckRequested = FALSE;
1675         KeBugCheck(MANUALLY_INITIATED_CRASH);
1676     }
1677 
1678 continue_execution:
1679     /* Clear debug status */
1680     if (ExceptionCode == STATUS_BREAKPOINT) /* FIXME: Why clear DR6 on INT3? */
1681     {
1682         /* Set the RF flag so we don't trigger the same breakpoint again. */
1683         if (Resume)
1684         {
1685             TrapFrame->EFlags |= EFLAGS_RF;
1686         }
1687 
1688         /* Clear dr6 status flags. */
1689         TrapFrame->Dr6 &= ~0x0000e00f;
1690 
1691         if (!(KdbEnteredOnSingleStep && KdbSingleStepOver))
1692         {
1693             /* Skip the current instruction */
1694             Context->Eip++;
1695         }
1696     }
1697 
1698     return ContinueType;
1699 }
1700 
1701 VOID
1702 NTAPI
1703 INIT_FUNCTION
1704 KdbpGetCommandLineSettings(
1705     PCHAR p1)
1706 {
1707 #define CONST_STR_LEN(x) (sizeof(x)/sizeof(x[0]) - 1)
1708 
1709     while (p1 && (p1 = strchr(p1, ' ')))
1710     {
1711         /* Skip other spaces */
1712         while (*p1 == ' ') ++p1;
1713 
1714         if (!_strnicmp(p1, "KDSERIAL", CONST_STR_LEN("KDSERIAL")))
1715         {
1716             p1 += CONST_STR_LEN("KDSERIAL");
1717             KdbDebugState |= KD_DEBUG_KDSERIAL;
1718             KdpDebugMode.Serial = TRUE;
1719         }
1720         else if (!_strnicmp(p1, "KDNOECHO", CONST_STR_LEN("KDNOECHO")))
1721         {
1722             p1 += CONST_STR_LEN("KDNOECHO");
1723             KdbDebugState |= KD_DEBUG_KDNOECHO;
1724         }
1725         else if (!_strnicmp(p1, "FIRSTCHANCE", CONST_STR_LEN("FIRSTCHANCE")))
1726         {
1727             p1 += CONST_STR_LEN("FIRSTCHANCE");
1728             KdbpSetEnterCondition(-1, TRUE, KdbEnterAlways);
1729         }
1730     }
1731 }
1732 
1733 NTSTATUS
1734 KdbpSafeReadMemory(
1735     OUT PVOID Dest,
1736     IN PVOID Src,
1737     IN ULONG Bytes)
1738 {
1739     BOOLEAN Result = TRUE;
1740 
1741     switch (Bytes)
1742     {
1743         case 1:
1744         case 2:
1745         case 4:
1746         case 8:
1747             Result = KdpSafeReadMemory((ULONG_PTR)Src, Bytes, Dest);
1748             break;
1749 
1750         default:
1751         {
1752             ULONG_PTR Start, End, Write;
1753 
1754             for (Start = (ULONG_PTR)Src,
1755                     End = Start + Bytes,
1756                     Write = (ULONG_PTR)Dest;
1757                  Result && (Start < End);
1758                  Start++, Write++)
1759                 if (!KdpSafeReadMemory(Start, 1, (PVOID)Write))
1760                     Result = FALSE;
1761 
1762             break;
1763         }
1764     }
1765 
1766     return Result ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION;
1767 }
1768 
1769 NTSTATUS
1770 KdbpSafeWriteMemory(
1771     OUT PVOID Dest,
1772     IN PVOID Src,
1773     IN ULONG Bytes)
1774 {
1775     BOOLEAN Result = TRUE;
1776     ULONG_PTR Start, End, Write;
1777 
1778     for (Start = (ULONG_PTR)Src,
1779             End = Start + Bytes,
1780             Write = (ULONG_PTR)Dest;
1781          Result && (Start < End);
1782          Start++, Write++)
1783         if (!KdpSafeWriteMemory(Write, 1, *((PCHAR)Start)))
1784             Result = FALSE;
1785 
1786     return Result ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION;
1787 }
1788