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