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