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