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