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