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