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