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