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