Sync trunk r40500
[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 ObDereferenceObject(Thread);
1088 return FALSE;
1089 }
1090
1091 /* Save the current thread's context (if we previously attached to a thread) */
1092 if (KdbCurrentThread != KdbOriginalThread)
1093 {
1094 ASSERT(KdbCurrentTrapFrame == &KdbThreadTrapFrame);
1095 /* Actually, we can't save the context, there's no guarantee that there
1096 * was a trap frame */
1097 }
1098 else
1099 {
1100 ASSERT(KdbCurrentTrapFrame == &KdbTrapFrame);
1101 }
1102
1103 /* Switch to the thread's context */
1104 if (Thread != KdbOriginalThread)
1105 {
1106 /* The thread we're attaching to isn't the thread on which we entered
1107 * kdb and so the thread we're attaching to is not running. There
1108 * is no guarantee that it actually has a trap frame. So we have to
1109 * peek directly at the registers which were saved on the stack when the
1110 * thread was preempted in the scheduler */
1111 KdbpKdbTrapFrameFromKernelStack(Thread->Tcb.KernelStack,
1112 &KdbThreadTrapFrame);
1113 KdbCurrentTrapFrame = &KdbThreadTrapFrame;
1114 }
1115 else /* Switching back to original thread */
1116 {
1117 KdbCurrentTrapFrame = &KdbTrapFrame;
1118 }
1119 KdbCurrentThread = Thread;
1120
1121 /* Attach to the thread's process */
1122 ASSERT(KdbCurrentProcess == PsGetCurrentProcess());
1123 if (KdbCurrentProcess != Process)
1124 {
1125 if (KdbCurrentProcess != KdbOriginalProcess) /* detach from previously attached process */
1126 {
1127 KeUnstackDetachProcess(&KdbApcState);
1128 }
1129 if (KdbOriginalProcess != Process)
1130 {
1131 KeStackAttachProcess(&Process->Pcb, &KdbApcState);
1132 }
1133 KdbCurrentProcess = Process;
1134 }
1135
1136 ObDereferenceObject(Thread);
1137 return TRUE;
1138 }
1139
1140 /*!\brief Switches to another process/thread context
1141 *
1142 * This function switches to the first thread in the specified process.
1143 *
1144 * \param ProcessId Id of the process to switch to.
1145 *
1146 * \retval TRUE Success.
1147 * \retval FALSE Failure (i.e. invalid process id)
1148 */
1149 BOOLEAN
1150 KdbpAttachToProcess(
1151 PVOID ProcessId)
1152 {
1153 PEPROCESS Process = NULL;
1154 PETHREAD Thread;
1155 PLIST_ENTRY Entry;
1156
1157 /* Get a pointer to the process */
1158 if (!NT_SUCCESS(PsLookupProcessByProcessId(ProcessId, &Process)))
1159 {
1160 KdbpPrint("Invalid process id: 0x%08x\n", (ULONG_PTR)ProcessId);
1161 return FALSE;
1162 }
1163
1164 Entry = Process->ThreadListHead.Flink;
1165 ObDereferenceObject(Process);
1166 if (Entry == &KdbCurrentProcess->ThreadListHead)
1167 {
1168 KdbpPrint("No threads in process 0x%p, cannot attach to process!\n", ProcessId);
1169 return FALSE;
1170 }
1171
1172 Thread = CONTAINING_RECORD(Entry, ETHREAD, ThreadListEntry);
1173
1174 return KdbpAttachToThread(Thread->Cid.UniqueThread);
1175 }
1176
1177 /*!\brief Calls the main loop ...
1178 */
1179 STATIC VOID
1180 KdbpCallMainLoop()
1181 {
1182 KdbpCliMainLoop(KdbEnteredOnSingleStep);
1183 }
1184
1185 /*!\brief Internal function to enter KDB.
1186 *
1187 * Disables interrupts, releases display ownership, ...
1188 */
1189 STATIC VOID
1190 KdbpInternalEnter()
1191 {
1192 PETHREAD Thread;
1193 PVOID SavedInitialStack, SavedStackBase, SavedKernelStack;
1194 ULONG SavedStackLimit;
1195
1196 KbdDisableMouse();
1197 if (KdpDebugMode.Screen)
1198 {
1199 InbvAcquireDisplayOwnership();
1200 }
1201
1202 /* Call the interface's main loop on a different stack */
1203 Thread = PsGetCurrentThread();
1204 SavedInitialStack = Thread->Tcb.InitialStack;
1205 SavedStackBase = Thread->Tcb.StackBase;
1206 SavedStackLimit = Thread->Tcb.StackLimit;
1207 SavedKernelStack = Thread->Tcb.KernelStack;
1208 Thread->Tcb.InitialStack = Thread->Tcb.StackBase = (char*)KdbStack + KDB_STACK_SIZE;
1209 Thread->Tcb.StackLimit = (ULONG_PTR)KdbStack;
1210 Thread->Tcb.KernelStack = (char*)KdbStack + KDB_STACK_SIZE;
1211
1212 /*KdbpPrint("Switching to KDB stack 0x%08x-0x%08x (Current Stack is 0x%08x)\n", Thread->Tcb.StackLimit, Thread->Tcb.StackBase, Esp);*/
1213
1214 KdbpStackSwitchAndCall(KdbStack + KDB_STACK_SIZE - sizeof(ULONG), KdbpCallMainLoop);
1215
1216 Thread->Tcb.InitialStack = SavedInitialStack;
1217 Thread->Tcb.StackBase = SavedStackBase;
1218 Thread->Tcb.StackLimit = SavedStackLimit;
1219 Thread->Tcb.KernelStack = SavedKernelStack;
1220 KbdEnableMouse();
1221 }
1222
1223 STATIC ULONG
1224 KdbpGetExceptionNumberFromStatus(IN NTSTATUS ExceptionCode)
1225 {
1226 ULONG Ret;
1227
1228 switch (ExceptionCode)
1229 {
1230 case STATUS_INTEGER_DIVIDE_BY_ZERO:
1231 Ret = 0;
1232 break;
1233 case STATUS_SINGLE_STEP:
1234 Ret = 1;
1235 break;
1236 case STATUS_BREAKPOINT:
1237 Ret = 3;
1238 break;
1239 case STATUS_INTEGER_OVERFLOW:
1240 Ret = 4;
1241 break;
1242 case STATUS_ARRAY_BOUNDS_EXCEEDED:
1243 Ret = 5;
1244 break;
1245 case STATUS_ILLEGAL_INSTRUCTION:
1246 Ret = 6;
1247 break;
1248 case STATUS_FLOAT_INVALID_OPERATION:
1249 Ret = 7;
1250 break;
1251 case STATUS_STACK_OVERFLOW:
1252 Ret = 12;
1253 break;
1254 case STATUS_ACCESS_VIOLATION:
1255 Ret = 14;
1256 break;
1257 case STATUS_DATATYPE_MISALIGNMENT:
1258 Ret = 17;
1259 break;
1260 case STATUS_FLOAT_MULTIPLE_TRAPS:
1261 Ret = 18;
1262 break;
1263
1264 default:
1265 Ret = RTL_NUMBER_OF(KdbEnterConditions) - 1;
1266 break;
1267 }
1268
1269 return Ret;
1270 }
1271
1272 /*!\brief KDB Exception filter
1273 *
1274 * Called by the exception dispatcher.
1275 *
1276 * \param ExceptionRecord Unused.
1277 * \param PreviousMode UserMode if the exception was raised from umode, otherwise KernelMode.
1278 * \param Context Context, IN/OUT parameter.
1279 * \param TrapFrame Exception TrapFrame.
1280 * \param FirstChance TRUE when called before exception frames were serached,
1281 * FALSE for the second call.
1282 *
1283 * \returns KD_CONTINUE_TYPE
1284 */
1285 KD_CONTINUE_TYPE
1286 KdbEnterDebuggerException(
1287 IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL,
1288 IN KPROCESSOR_MODE PreviousMode,
1289 IN PCONTEXT Context,
1290 IN OUT PKTRAP_FRAME TrapFrame,
1291 IN BOOLEAN FirstChance)
1292 {
1293 KDB_ENTER_CONDITION EnterCondition;
1294 KD_CONTINUE_TYPE ContinueType = kdHandleException;
1295 PKDB_BREAKPOINT BreakPoint;
1296 ULONG ExpNr;
1297 ULONGLONG ull;
1298 BOOLEAN Resume = FALSE;
1299 BOOLEAN EnterConditionMet = TRUE;
1300 ULONG OldEflags;
1301 NTSTATUS ExceptionCode;
1302
1303 ExceptionCode = (ExceptionRecord != NULL ? ExceptionRecord->ExceptionCode : STATUS_BREAKPOINT);
1304
1305 KdbCurrentProcess = PsGetCurrentProcess();
1306
1307 /* Set continue type to kdContinue for single steps and breakpoints */
1308 if (ExceptionCode == STATUS_SINGLE_STEP || ExceptionCode == STATUS_BREAKPOINT)
1309 ContinueType = kdContinue;
1310
1311 /* Check if we should handle the exception. */
1312 /* FIXME - won't get all exceptions here :( */
1313 ExpNr = KdbpGetExceptionNumberFromStatus(ExceptionCode);
1314 EnterCondition = KdbEnterConditions[ExpNr][FirstChance ? 0 : 1];
1315 if (EnterCondition == KdbDoNotEnter ||
1316 (EnterCondition == KdbEnterFromUmode && PreviousMode == KernelMode) ||
1317 (EnterCondition == KdbEnterFromKmode && PreviousMode != KernelMode))
1318 {
1319 EnterConditionMet = FALSE;
1320 }
1321
1322 /* If we stopped on one of our breakpoints then let the user know. */
1323 KdbLastBreakPointNr = -1;
1324 KdbEnteredOnSingleStep = FALSE;
1325
1326 if (FirstChance && (ExceptionCode == STATUS_SINGLE_STEP || ExceptionCode == STATUS_BREAKPOINT) &&
1327 (KdbLastBreakPointNr = KdbpIsBreakPointOurs(ExceptionCode, TrapFrame)) >= 0)
1328 {
1329 BreakPoint = KdbBreakPoints + KdbLastBreakPointNr;
1330
1331 if (ExceptionCode == STATUS_BREAKPOINT)
1332 {
1333 /*
1334 * ... and restore the original instruction.
1335 */
1336 if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess, BreakPoint->Address,
1337 BreakPoint->Data.SavedInstruction, NULL)))
1338 {
1339 KdbpPrint("Couldn't restore original instruction after INT3! Cannot continue execution.\n");
1340 KeBugCheck(0); // FIXME: Proper bugcode!
1341 }
1342 }
1343
1344 if ((BreakPoint->Type == KdbBreakPointHardware) &&
1345 (BreakPoint->Data.Hw.AccessType == KdbAccessExec))
1346 {
1347 Resume = TRUE; /* Set the resume flag when continuing execution */
1348 }
1349
1350 /*
1351 * When a temporary breakpoint is hit we have to make sure that we are
1352 * in the same context in which it was set, otherwise it could happen
1353 * that another process/thread hits it before and it gets deleted.
1354 */
1355 else if (BreakPoint->Type == KdbBreakPointTemporary &&
1356 BreakPoint->Process == KdbCurrentProcess)
1357 {
1358 ASSERT((TrapFrame->EFlags & EFLAGS_TF) == 0);
1359
1360 /*
1361 * Delete the temporary breakpoint which was used to step over or into the instruction.
1362 */
1363 KdbpDeleteBreakPoint(-1, BreakPoint);
1364
1365 if (--KdbNumSingleSteps > 0)
1366 {
1367 if ((KdbSingleStepOver && !KdbpStepOverInstruction(TrapFrame->Eip)) ||
1368 (!KdbSingleStepOver && !KdbpStepIntoInstruction(TrapFrame->Eip)))
1369 {
1370 Context->EFlags |= EFLAGS_TF;
1371 }
1372 goto continue_execution; /* return */
1373 }
1374
1375 KdbEnteredOnSingleStep = TRUE;
1376 }
1377
1378 /*
1379 * If we hit a breakpoint set by the debugger we set the single step flag,
1380 * ignore the next single step and reenable the breakpoint.
1381 */
1382 else if (BreakPoint->Type == KdbBreakPointSoftware ||
1383 BreakPoint->Type == KdbBreakPointTemporary)
1384 {
1385 ASSERT(ExceptionCode == STATUS_BREAKPOINT);
1386 Context->EFlags |= EFLAGS_TF;
1387 KdbBreakPointToReenable = BreakPoint;
1388 }
1389
1390 /*
1391 * Make sure that the breakpoint should be triggered in this context
1392 */
1393 if (!BreakPoint->Global && BreakPoint->Process != KdbCurrentProcess)
1394 {
1395 goto continue_execution; /* return */
1396 }
1397
1398 /*
1399 * Check if the condition for the breakpoint is met.
1400 */
1401 if (BreakPoint->Condition != NULL)
1402 {
1403 /* Setup the KDB trap frame */
1404 KdbpTrapFrameToKdbTrapFrame(TrapFrame, &KdbTrapFrame);
1405
1406 ull = 0;
1407 if (!KdbpRpnEvaluateParsedExpression(BreakPoint->Condition, &KdbTrapFrame, &ull, NULL, NULL))
1408 {
1409 /* FIXME: Print warning? */
1410 }
1411 else if (ull == 0) /* condition is not met */
1412 {
1413 goto continue_execution; /* return */
1414 }
1415 }
1416
1417 if (BreakPoint->Type == KdbBreakPointSoftware)
1418 {
1419 KdbpPrint("Entered debugger on breakpoint #%d: EXEC 0x%04x:0x%08x\n",
1420 KdbLastBreakPointNr, TrapFrame->SegCs & 0xffff, TrapFrame->Eip);
1421 }
1422 else if (BreakPoint->Type == KdbBreakPointHardware)
1423 {
1424 KdbpPrint("Entered debugger on breakpoint #%d: %s 0x%08x\n",
1425 KdbLastBreakPointNr,
1426 (BreakPoint->Data.Hw.AccessType == KdbAccessRead) ? "READ" :
1427 ((BreakPoint->Data.Hw.AccessType == KdbAccessWrite) ? "WRITE" :
1428 ((BreakPoint->Data.Hw.AccessType == KdbAccessReadWrite) ? "RDWR" : "EXEC")
1429 ),
1430 BreakPoint->Address
1431 );
1432
1433 }
1434 }
1435 else if (ExceptionCode == STATUS_SINGLE_STEP)
1436 {
1437 /* Silently ignore a debugger initiated single step. */
1438 if ((TrapFrame->Dr6 & 0xf) == 0 && KdbBreakPointToReenable != NULL)
1439 {
1440 /* FIXME: Make sure that the breakpoint was really hit (check bp->Address vs. tf->Eip) */
1441 BreakPoint = KdbBreakPointToReenable;
1442 KdbBreakPointToReenable = NULL;
1443 ASSERT(BreakPoint->Type == KdbBreakPointSoftware ||
1444 BreakPoint->Type == KdbBreakPointTemporary);
1445
1446 /*
1447 * Reenable the breakpoint we disabled to execute the breakpointed
1448 * instruction.
1449 */
1450 if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess, BreakPoint->Address, 0xCC,
1451 &BreakPoint->Data.SavedInstruction)))
1452 {
1453 KdbpPrint("Warning: Couldn't reenable breakpoint %d\n",
1454 BreakPoint - KdbBreakPoints);
1455 }
1456
1457 /* Unset TF if we are no longer single stepping. */
1458 if (KdbNumSingleSteps == 0)
1459 Context->EFlags &= ~EFLAGS_TF;
1460 goto continue_execution; /* return */
1461 }
1462
1463 /* Check if we expect a single step */
1464 if ((TrapFrame->Dr6 & 0xf) == 0 && KdbNumSingleSteps > 0)
1465 {
1466 /*ASSERT((Context->Eflags & EFLAGS_TF) != 0);*/
1467 if (--KdbNumSingleSteps > 0)
1468 {
1469 if ((KdbSingleStepOver && KdbpStepOverInstruction(TrapFrame->Eip)) ||
1470 (!KdbSingleStepOver && KdbpStepIntoInstruction(TrapFrame->Eip)))
1471 {
1472 Context->EFlags &= ~EFLAGS_TF;
1473 }
1474 else
1475 {
1476 Context->EFlags |= EFLAGS_TF;
1477 }
1478 goto continue_execution; /* return */
1479 }
1480 else
1481 {
1482 Context->EFlags &= ~EFLAGS_TF;
1483 KdbEnteredOnSingleStep = TRUE;
1484 }
1485 }
1486 else
1487 {
1488 if (!EnterConditionMet)
1489 {
1490 return kdHandleException;
1491 }
1492 KdbpPrint("Entered debugger on unexpected debug trap!\n");
1493 }
1494 }
1495 else if (ExceptionCode == STATUS_BREAKPOINT)
1496 {
1497 if (KdbInitFileBuffer != NULL)
1498 {
1499 KdbpCliInterpretInitFile();
1500 EnterConditionMet = FALSE;
1501 }
1502 if (!EnterConditionMet)
1503 {
1504 return kdHandleException;
1505 }
1506
1507 KdbpPrint("Entered debugger on embedded INT3 at 0x%04x:0x%08x.\n",
1508 TrapFrame->SegCs & 0xffff, TrapFrame->Eip - 1);
1509 }
1510 else
1511 {
1512 CONST CHAR *ExceptionString = (ExpNr < RTL_NUMBER_OF(ExceptionNrToString)) ?
1513 (ExceptionNrToString[ExpNr]) :
1514 ("Unknown/User defined exception");
1515
1516 if (!EnterConditionMet)
1517 {
1518 return ContinueType;
1519 }
1520
1521 KdbpPrint("Entered debugger on %s-chance exception (Exception Code: 0x%x) (%s)\n",
1522 FirstChance ? "first" : "last", ExceptionCode, ExceptionString);
1523 if (ExceptionCode == STATUS_ACCESS_VIOLATION &&
1524 ExceptionRecord != NULL && ExceptionRecord->NumberParameters != 0)
1525 {
1526 /* FIXME: Add noexec memory stuff */
1527 ULONG_PTR TrapCr2;
1528 ULONG Err;
1529 #ifdef __GNUC__
1530 asm volatile("movl %%cr2, %0" : "=r"(TrapCr2));
1531 #elif _MSC_VER
1532 __asm mov eax, cr2;
1533 __asm mov TrapCr2, eax;
1534 #else
1535 #error Unknown compiler for inline assembler
1536 #endif
1537
1538 Err = TrapFrame->ErrCode;
1539 KdbpPrint("Memory at 0x%p could not be %s: ", TrapCr2, (Err & (1 << 1)) ? "written" : "read");
1540 if ((Err & (1 << 0)) == 0)
1541 KdbpPrint("Page not present.\n");
1542 else
1543 {
1544 if ((Err & (1 << 3)) != 0)
1545 KdbpPrint("Reserved bits in page directory set.\n");
1546 else
1547 KdbpPrint("Page protection violation.\n");
1548 }
1549 }
1550 }
1551
1552 /* Once we enter the debugger we do not expect any more single steps to happen */
1553 KdbNumSingleSteps = 0;
1554
1555 /* Update the current process pointer */
1556 KdbCurrentProcess = KdbOriginalProcess = PsGetCurrentProcess();
1557 KdbCurrentThread = KdbOriginalThread = PsGetCurrentThread();
1558 KdbCurrentTrapFrame = &KdbTrapFrame;
1559
1560 /* Setup the KDB trap frame */
1561 KdbpTrapFrameToKdbTrapFrame(TrapFrame, &KdbTrapFrame);
1562
1563 /* Enter critical section */
1564 Ke386SaveFlags(OldEflags);
1565 _disable();
1566
1567 /* Exception inside the debugger? Game over. */
1568 if (InterlockedIncrement(&KdbEntryCount) > 1)
1569 {
1570 Ke386RestoreFlags(OldEflags);
1571 return kdHandleException;
1572 }
1573
1574 /* Call the main loop. */
1575 KdbpInternalEnter();
1576
1577 /* Check if we should single step */
1578 if (KdbNumSingleSteps > 0)
1579 {
1580 if ((KdbSingleStepOver && KdbpStepOverInstruction(KdbCurrentTrapFrame->Tf.Eip)) ||
1581 (!KdbSingleStepOver && KdbpStepIntoInstruction(KdbCurrentTrapFrame->Tf.Eip)))
1582 {
1583 ASSERT((KdbCurrentTrapFrame->Tf.EFlags & EFLAGS_TF) == 0);
1584 /*KdbCurrentTrapFrame->Tf.EFlags &= ~EFLAGS_TF;*/
1585 }
1586 else
1587 {
1588 Context->EFlags |= EFLAGS_TF;
1589 }
1590 }
1591
1592 /* We can't update the current thread's trapframe 'cause it might not
1593 have one */
1594
1595 /* Detach from attached process */
1596 if (KdbCurrentProcess != KdbOriginalProcess)
1597 {
1598 KeUnstackDetachProcess(&KdbApcState);
1599 }
1600
1601 /* Update the exception TrapFrame */
1602 KdbpKdbTrapFrameToTrapFrame(&KdbTrapFrame, TrapFrame);
1603
1604 /* Decrement the entry count */
1605 InterlockedDecrement(&KdbEntryCount);
1606
1607 /* Leave critical section */
1608 Ke386RestoreFlags(OldEflags);
1609
1610 /* Check if user requested a bugcheck */
1611 if (KdbpBugCheckRequested)
1612 {
1613 /* Clear the flag and bugcheck the system */
1614 KdbpBugCheckRequested = FALSE;
1615 KeBugCheck(MANUALLY_INITIATED_CRASH);
1616 }
1617
1618 continue_execution:
1619 /* Clear debug status */
1620 if (ExceptionCode == STATUS_BREAKPOINT) /* FIXME: Why clear DR6 on INT3? */
1621 {
1622 /* Set the RF flag so we don't trigger the same breakpoint again. */
1623 if (Resume)
1624 {
1625 TrapFrame->EFlags |= EFLAGS_RF;
1626 }
1627
1628 /* Clear dr6 status flags. */
1629 TrapFrame->Dr6 &= ~0x0000e00f;
1630
1631 /* Skip the current instruction */
1632 Context->Eip++;
1633 }
1634
1635 return ContinueType;
1636 }
1637
1638 VOID
1639 KdbDeleteProcessHook(IN PEPROCESS Process)
1640 {
1641 KdbSymFreeProcessSymbols(Process);
1642
1643 /* FIXME: Delete breakpoints for process */
1644 }
1645
1646 VOID
1647 NTAPI
1648 KdbpGetCommandLineSettings(PCHAR p1)
1649 {
1650 PCHAR p2;
1651
1652 while (p1 && (p2 = strchr(p1, ' ')))
1653 {
1654 p2++;
1655
1656 if (!_strnicmp(p2, "KDSERIAL", 8))
1657 {
1658 p2 += 8;
1659 KdbDebugState |= KD_DEBUG_KDSERIAL;
1660 KdpDebugMode.Serial = TRUE;
1661 }
1662 else if (!_strnicmp(p2, "KDNOECHO", 8))
1663 {
1664 p2 += 8;
1665 KdbDebugState |= KD_DEBUG_KDNOECHO;
1666 }
1667
1668 p1 = p2;
1669 }
1670 }
1671
1672 NTSTATUS
1673 KdbpSafeReadMemory(OUT PVOID Dest,
1674 IN PVOID Src,
1675 IN ULONG Bytes)
1676 {
1677 BOOLEAN Result = TRUE;
1678
1679 switch (Bytes)
1680 {
1681 case 1:
1682 case 2:
1683 case 4:
1684 case 8:
1685 Result = KdpSafeReadMemory((ULONG_PTR)Src, Bytes, Dest);
1686 break;
1687 default:
1688 {
1689 ULONG_PTR Start, End, Write;
1690 for (Start = (ULONG_PTR)Src,
1691 End = Start + Bytes,
1692 Write = (ULONG_PTR)Dest;
1693 Result && (Start < End);
1694 Start++, Write++)
1695 if (!KdpSafeReadMemory(Start, 1, (PVOID)Write))
1696 Result = FALSE;
1697 break;
1698 }
1699 }
1700
1701 return Result ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION;
1702 }
1703
1704 NTSTATUS
1705 KdbpSafeWriteMemory(OUT PVOID Dest,
1706 IN PVOID Src,
1707 IN ULONG Bytes)
1708 {
1709 BOOLEAN Result = TRUE;
1710 ULONG_PTR Start, End, Write;
1711
1712 for (Start = (ULONG_PTR)Src,
1713 End = Start + Bytes,
1714 Write = (ULONG_PTR)Dest;
1715 Result && (Start < End);
1716 Start++, Write++)
1717 if (!KdpSafeWriteMemory(Write, 1, *((PCHAR)Start)))
1718 Result = FALSE;
1719
1720 return Result ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION;
1721 }