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