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