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