[CMAKE]
[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 /* 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 #ifdef _M_IX86
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 TrapFrame->Eip--;
1417
1418 if (--KdbNumSingleSteps > 0)
1419 {
1420 if ((KdbSingleStepOver && !KdbpStepOverInstruction(TrapFrame->Eip)) ||
1421 (!KdbSingleStepOver && !KdbpStepIntoInstruction(TrapFrame->Eip)))
1422 {
1423 Context->EFlags |= EFLAGS_TF;
1424 }
1425
1426 goto continue_execution; /* return */
1427 }
1428
1429 KdbEnteredOnSingleStep = TRUE;
1430 }
1431
1432 /*
1433 * If we hit a breakpoint set by the debugger we set the single step flag,
1434 * ignore the next single step and reenable the breakpoint.
1435 */
1436 else if (BreakPoint->Type == KdbBreakPointSoftware ||
1437 BreakPoint->Type == KdbBreakPointTemporary)
1438 {
1439 ASSERT(ExceptionCode == STATUS_BREAKPOINT);
1440 Context->EFlags |= EFLAGS_TF;
1441 KdbBreakPointToReenable = BreakPoint;
1442 }
1443
1444 /* Make sure that the breakpoint should be triggered in this context */
1445 if (!BreakPoint->Global && BreakPoint->Process != KdbCurrentProcess)
1446 {
1447 goto continue_execution; /* return */
1448 }
1449
1450 /* Check if the condition for the breakpoint is met. */
1451 if (BreakPoint->Condition)
1452 {
1453 /* Setup the KDB trap frame */
1454 KdbpTrapFrameToKdbTrapFrame(TrapFrame, &KdbTrapFrame);
1455
1456 ull = 0;
1457 if (!KdbpRpnEvaluateParsedExpression(BreakPoint->Condition, &KdbTrapFrame, &ull, NULL, NULL))
1458 {
1459 /* FIXME: Print warning? */
1460 }
1461 else if (ull == 0) /* condition is not met */
1462 {
1463 goto continue_execution; /* return */
1464 }
1465 }
1466
1467 if (BreakPoint->Type == KdbBreakPointSoftware)
1468 {
1469 KdbpPrint("Entered debugger on breakpoint #%d: EXEC 0x%04x:0x%08x\n",
1470 KdbLastBreakPointNr, TrapFrame->SegCs & 0xffff, TrapFrame->Eip);
1471 }
1472 else if (BreakPoint->Type == KdbBreakPointHardware)
1473 {
1474 KdbpPrint("Entered debugger on breakpoint #%d: %s 0x%08x\n",
1475 KdbLastBreakPointNr,
1476 (BreakPoint->Data.Hw.AccessType == KdbAccessRead) ? "READ" :
1477 ((BreakPoint->Data.Hw.AccessType == KdbAccessWrite) ? "WRITE" :
1478 ((BreakPoint->Data.Hw.AccessType == KdbAccessReadWrite) ? "RDWR" : "EXEC")),
1479 BreakPoint->Address);
1480 }
1481 }
1482 else if (ExceptionCode == STATUS_SINGLE_STEP)
1483 {
1484 /* Silently ignore a debugger initiated single step. */
1485 if ((TrapFrame->Dr6 & 0xf) == 0 && KdbBreakPointToReenable)
1486 {
1487 /* FIXME: Make sure that the breakpoint was really hit (check bp->Address vs. tf->Eip) */
1488 BreakPoint = KdbBreakPointToReenable;
1489 KdbBreakPointToReenable = NULL;
1490 ASSERT(BreakPoint->Type == KdbBreakPointSoftware ||
1491 BreakPoint->Type == KdbBreakPointTemporary);
1492
1493 /*
1494 * Reenable the breakpoint we disabled to execute the breakpointed
1495 * instruction.
1496 */
1497 if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess, BreakPoint->Address, 0xCC,
1498 &BreakPoint->Data.SavedInstruction)))
1499 {
1500 KdbpPrint("Warning: Couldn't reenable breakpoint %d\n",
1501 BreakPoint - KdbBreakPoints);
1502 }
1503
1504 /* Unset TF if we are no longer single stepping. */
1505 if (KdbNumSingleSteps == 0)
1506 Context->EFlags &= ~EFLAGS_TF;
1507
1508 goto continue_execution; /* return */
1509 }
1510
1511 /* Check if we expect a single step */
1512 if ((TrapFrame->Dr6 & 0xf) == 0 && KdbNumSingleSteps > 0)
1513 {
1514 /*ASSERT((Context->Eflags & EFLAGS_TF) != 0);*/
1515 if (--KdbNumSingleSteps > 0)
1516 {
1517 if ((KdbSingleStepOver && KdbpStepOverInstruction(TrapFrame->Eip)) ||
1518 (!KdbSingleStepOver && KdbpStepIntoInstruction(TrapFrame->Eip)))
1519 {
1520 Context->EFlags &= ~EFLAGS_TF;
1521 }
1522 else
1523 {
1524 Context->EFlags |= EFLAGS_TF;
1525 }
1526
1527 goto continue_execution; /* return */
1528 }
1529 else
1530 {
1531 Context->EFlags &= ~EFLAGS_TF;
1532 KdbEnteredOnSingleStep = TRUE;
1533 }
1534 }
1535 else
1536 {
1537 if (!EnterConditionMet)
1538 {
1539 return kdHandleException;
1540 }
1541
1542 KdbpPrint("Entered debugger on unexpected debug trap!\n");
1543 }
1544 }
1545 else if (ExceptionCode == STATUS_BREAKPOINT)
1546 {
1547 if (KdbInitFileBuffer)
1548 {
1549 KdbpCliInterpretInitFile();
1550 EnterConditionMet = FALSE;
1551 }
1552 if (!EnterConditionMet)
1553 {
1554 return kdHandleException;
1555 }
1556
1557 KdbpPrint("Entered debugger on embedded INT3 at 0x%04x:0x%08x.\n",
1558 TrapFrame->SegCs & 0xffff, TrapFrame->Eip - 1);
1559 }
1560 else
1561 {
1562 const CHAR *ExceptionString = (ExpNr < RTL_NUMBER_OF(ExceptionNrToString)) ?
1563 (ExceptionNrToString[ExpNr]) :
1564 ("Unknown/User defined exception");
1565
1566 if (!EnterConditionMet)
1567 {
1568 return ContinueType;
1569 }
1570
1571 KdbpPrint("Entered debugger on %s-chance exception (Exception Code: 0x%x) (%s)\n",
1572 FirstChance ? "first" : "last", ExceptionCode, ExceptionString);
1573
1574 if (ExceptionCode == STATUS_ACCESS_VIOLATION &&
1575 ExceptionRecord && ExceptionRecord->NumberParameters != 0)
1576 {
1577 /* FIXME: Add noexec memory stuff */
1578 ULONG_PTR TrapCr2;
1579 ULONG Err;
1580
1581 TrapCr2 = __readcr2();
1582
1583 Err = TrapFrame->ErrCode;
1584 KdbpPrint("Memory at 0x%p could not be %s: ", TrapCr2, (Err & (1 << 1)) ? "written" : "read");
1585
1586 if ((Err & (1 << 0)) == 0)
1587 {
1588 KdbpPrint("Page not present.\n");
1589 }
1590 else
1591 {
1592 if ((Err & (1 << 3)) != 0)
1593 KdbpPrint("Reserved bits in page directory set.\n");
1594 else
1595 KdbpPrint("Page protection violation.\n");
1596 }
1597 }
1598 }
1599
1600 /* Once we enter the debugger we do not expect any more single steps to happen */
1601 KdbNumSingleSteps = 0;
1602
1603 /* Update the current process pointer */
1604 KdbCurrentProcess = KdbOriginalProcess = PsGetCurrentProcess();
1605 KdbCurrentThread = KdbOriginalThread = PsGetCurrentThread();
1606 KdbCurrentTrapFrame = &KdbTrapFrame;
1607
1608 /* Setup the KDB trap frame */
1609 KdbpTrapFrameToKdbTrapFrame(TrapFrame, &KdbTrapFrame);
1610
1611 /* Enter critical section */
1612 OldEflags = __readeflags();
1613 _disable();
1614
1615 /* HACK: Save the current IRQL and pretend we are at passive level,
1616 * although interrupts are off. Needed because KDBG calls pageable code. */
1617 OldIrql = KeGetCurrentIrql();
1618 KeLowerIrql(PASSIVE_LEVEL);
1619
1620 /* Exception inside the debugger? Game over. */
1621 if (InterlockedIncrement(&KdbEntryCount) > 1)
1622 {
1623 __writeeflags(OldEflags);
1624 return kdHandleException;
1625 }
1626
1627 /* Call the main loop. */
1628 KdbpInternalEnter();
1629
1630 /* Check if we should single step */
1631 if (KdbNumSingleSteps > 0)
1632 {
1633 if ((KdbSingleStepOver && KdbpStepOverInstruction(KdbCurrentTrapFrame->Tf.Eip)) ||
1634 (!KdbSingleStepOver && KdbpStepIntoInstruction(KdbCurrentTrapFrame->Tf.Eip)))
1635 {
1636 ASSERT((KdbCurrentTrapFrame->Tf.EFlags & EFLAGS_TF) == 0);
1637 /*KdbCurrentTrapFrame->Tf.EFlags &= ~EFLAGS_TF;*/
1638 }
1639 else
1640 {
1641 Context->EFlags |= EFLAGS_TF;
1642 }
1643 }
1644
1645 /* We can't update the current thread's trapframe 'cause it might not have one */
1646
1647 /* Detach from attached process */
1648 if (KdbCurrentProcess != KdbOriginalProcess)
1649 {
1650 KeUnstackDetachProcess(&KdbApcState);
1651 }
1652
1653 /* Update the exception TrapFrame */
1654 KdbpKdbTrapFrameToTrapFrame(&KdbTrapFrame, TrapFrame);
1655
1656 /* Decrement the entry count */
1657 InterlockedDecrement(&KdbEntryCount);
1658
1659 /* HACK: Raise back to old IRWL */
1660 KeRaiseIrql(OldIrql, &OldIrql);
1661
1662 /* Leave critical section */
1663 __writeeflags(OldEflags);
1664
1665 /* Check if user requested a bugcheck */
1666 if (KdbpBugCheckRequested)
1667 {
1668 /* Clear the flag and bugcheck the system */
1669 KdbpBugCheckRequested = FALSE;
1670 KeBugCheck(MANUALLY_INITIATED_CRASH);
1671 }
1672
1673 continue_execution:
1674 /* Clear debug status */
1675 if (ExceptionCode == STATUS_BREAKPOINT) /* FIXME: Why clear DR6 on INT3? */
1676 {
1677 /* Set the RF flag so we don't trigger the same breakpoint again. */
1678 if (Resume)
1679 {
1680 TrapFrame->EFlags |= EFLAGS_RF;
1681 }
1682
1683 /* Clear dr6 status flags. */
1684 TrapFrame->Dr6 &= ~0x0000e00f;
1685
1686 if (!(KdbEnteredOnSingleStep && KdbSingleStepOver))
1687 {
1688 /* Skip the current instruction */
1689 Context->Eip++;
1690 }
1691 }
1692
1693 return ContinueType;
1694 }
1695
1696 VOID
1697 NTAPI
1698 INIT_FUNCTION
1699 KdbpGetCommandLineSettings(
1700 PCHAR p1)
1701 {
1702 PCHAR p2;
1703
1704 while (p1 && (p2 = strchr(p1, ' ')))
1705 {
1706 p2 += 2;
1707
1708 if (!_strnicmp(p2, "KDSERIAL", 8))
1709 {
1710 p2 += 8;
1711 KdbDebugState |= KD_DEBUG_KDSERIAL;
1712 KdpDebugMode.Serial = TRUE;
1713 }
1714 else if (!_strnicmp(p2, "KDNOECHO", 8))
1715 {
1716 p2 += 8;
1717 KdbDebugState |= KD_DEBUG_KDNOECHO;
1718 }
1719 else if (!_strnicmp(p2, "FIRSTCHANCE", 11))
1720 {
1721 p2 += 11;
1722 KdbpSetEnterCondition(-1, TRUE, KdbEnterAlways);
1723 }
1724
1725 p1 = p2;
1726 }
1727 }
1728
1729 NTSTATUS
1730 KdbpSafeReadMemory(
1731 OUT PVOID Dest,
1732 IN PVOID Src,
1733 IN ULONG Bytes)
1734 {
1735 BOOLEAN Result = TRUE;
1736
1737 switch (Bytes)
1738 {
1739 case 1:
1740 case 2:
1741 case 4:
1742 case 8:
1743 Result = KdpSafeReadMemory((ULONG_PTR)Src, Bytes, Dest);
1744 break;
1745
1746 default:
1747 {
1748 ULONG_PTR Start, End, Write;
1749
1750 for (Start = (ULONG_PTR)Src,
1751 End = Start + Bytes,
1752 Write = (ULONG_PTR)Dest;
1753 Result && (Start < End);
1754 Start++, Write++)
1755 if (!KdpSafeReadMemory(Start, 1, (PVOID)Write))
1756 Result = FALSE;
1757
1758 break;
1759 }
1760 }
1761
1762 return Result ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION;
1763 }
1764
1765 NTSTATUS
1766 KdbpSafeWriteMemory(
1767 OUT PVOID Dest,
1768 IN PVOID Src,
1769 IN ULONG Bytes)
1770 {
1771 BOOLEAN Result = TRUE;
1772 ULONG_PTR Start, End, Write;
1773
1774 for (Start = (ULONG_PTR)Src,
1775 End = Start + Bytes,
1776 Write = (ULONG_PTR)Dest;
1777 Result && (Start < End);
1778 Start++, Write++)
1779 if (!KdpSafeWriteMemory(Write, 1, *((PCHAR)Start)))
1780 Result = FALSE;
1781
1782 return Result ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION;
1783 }