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