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