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