2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/kdbg/kdb.c
5 * PURPOSE: Kernel Debugger
7 * PROGRAMMERS: Gregor Anich
10 /* INCLUDES ******************************************************************/
16 /* TYPES *********************************************************************/
18 /* DEFINES *******************************************************************/
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
25 #define __STRING(x) #x
26 #define _STRING(x) __STRING(x)
28 /* GLOBALS *******************************************************************/
30 static LONG KdbEntryCount
= 0;
31 static CHAR KdbStack
[KDB_STACK_SIZE
];
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 static BOOLEAN KdbpEvenThoughWeHaveABreakPointToReenableWeAlsoHaveARealSingleStep
;
42 LONG KdbLastBreakPointNr
= -1; /* Index of the breakpoint which cause KDB to be entered */
43 ULONG KdbNumSingleSteps
= 0; /* How many single steps to do */
44 BOOLEAN KdbSingleStepOver
= FALSE
; /* Whether to step over calls/reps. */
45 ULONG KdbDebugState
= 0; /* KDBG Settings (NOECHO, KDSERIAL) */
46 static BOOLEAN KdbEnteredOnSingleStep
= FALSE
; /* Set to true when KDB was entered because of single step */
47 PEPROCESS KdbCurrentProcess
= NULL
; /* The current process context in which KDB runs */
48 PEPROCESS KdbOriginalProcess
= NULL
; /* The process in whichs context KDB was intered */
49 PETHREAD KdbCurrentThread
= NULL
; /* The current thread context in which KDB runs */
50 PETHREAD KdbOriginalThread
= NULL
; /* The thread in whichs context KDB was entered */
51 PKDB_KTRAP_FRAME KdbCurrentTrapFrame
= NULL
; /* Pointer to the current trapframe */
52 static KDB_KTRAP_FRAME KdbTrapFrame
= { { 0 } }; /* The trapframe which was passed to KdbEnterDebuggerException */
53 static KDB_KTRAP_FRAME KdbThreadTrapFrame
= { { 0 } }; /* The trapframe of the current thread (KdbCurrentThread) */
54 static KAPC_STATE KdbApcState
;
55 extern BOOLEAN KdbpBugCheckRequested
;
57 /* Array of conditions when to enter KDB */
58 static KDB_ENTER_CONDITION KdbEnterConditions
[][2] =
60 /* First chance Last chance */
61 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 0: Zero divide */
62 { KdbEnterFromKmode
, KdbDoNotEnter
}, /* 1: Debug trap */
63 { KdbDoNotEnter
, KdbEnterAlways
}, /* 2: NMI */
64 { KdbEnterFromKmode
, KdbDoNotEnter
}, /* 3: INT3 */
65 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 4: Overflow */
66 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 5: BOUND range exceeded */
67 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 6: Invalid opcode */
68 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 7: No math coprocessor fault */
69 { KdbEnterAlways
, KdbEnterAlways
}, /* 8: Double Fault */
70 { KdbEnterAlways
, KdbEnterAlways
}, /* 9: Unknown(9) */
71 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 10: Invalid TSS */
72 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 11: Segment Not Present */
73 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 12: Stack fault */
74 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 13: General protection fault */
75 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 14: Page fault */
76 { KdbEnterAlways
, KdbEnterAlways
}, /* 15: Reserved (15) */
77 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 16: FPU fault */
78 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 17: Alignment Check */
79 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 18: Machine Check */
80 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 19: SIMD fault */
81 { KdbEnterFromKmode
, KdbDoNotEnter
}, /* 20: Assertion failure */
82 { KdbDoNotEnter
, KdbEnterFromKmode
} /* Last entry: used for unknown exceptions */
85 /* Exception descriptions */
86 static const CHAR
*ExceptionNrToString
[] =
93 "BOUND range exceeded",
95 "No Math Coprocessor",
99 "Segment Not Present",
100 "Stack Segment Fault",
101 "General Protection",
114 IN PKTRAP_FRAME TrapFrame
);
119 IN PKTRAP_FRAME TrapFrame
);
124 IN PKTRAP_FRAME TrapFrame
,
130 IN PKTRAP_FRAME TrapFrame
,
133 /* FUNCTIONS *****************************************************************/
136 KdbpTrapFrameToKdbTrapFrame(
138 PKTRAP_FRAME TrapFrame
,
139 PKDB_KTRAP_FRAME KdbTrapFrame
)
143 KdbTrapFrame
->Tf
= *Context
;
149 RtlZeroMemory(KdbTrapFrame
, sizeof(KDB_KTRAP_FRAME
));
150 KdbTrapFrame
->Tf
.Dr0
= TrapFrame
->Dr0
;
151 KdbTrapFrame
->Tf
.Dr1
= TrapFrame
->Dr1
;
152 KdbTrapFrame
->Tf
.Dr2
= TrapFrame
->Dr2
;
153 KdbTrapFrame
->Tf
.Dr3
= TrapFrame
->Dr3
;
154 KdbTrapFrame
->Tf
.Dr6
= TrapFrame
->Dr6
;
155 KdbTrapFrame
->Tf
.Dr7
= TrapFrame
->Dr7
;
156 KdbTrapFrame
->Tf
.SegGs
= TrapFrame
->SegGs
;
157 KdbTrapFrame
->Tf
.SegEs
= TrapFrame
->SegEs
;
158 KdbTrapFrame
->Tf
.SegDs
= TrapFrame
->SegDs
;
159 KdbTrapFrame
->Tf
.Edx
= TrapFrame
->Edx
;
160 KdbTrapFrame
->Tf
.Ecx
= TrapFrame
->Ecx
;
161 KdbTrapFrame
->Tf
.Eax
= TrapFrame
->Eax
;
162 KdbTrapFrame
->Tf
.SegFs
= TrapFrame
->SegFs
;
163 KdbTrapFrame
->Tf
.Edi
= TrapFrame
->Edi
;
164 KdbTrapFrame
->Tf
.Esi
= TrapFrame
->Esi
;
165 KdbTrapFrame
->Tf
.Ebx
= TrapFrame
->Ebx
;
166 KdbTrapFrame
->Tf
.Ebp
= TrapFrame
->Ebp
;
167 KdbTrapFrame
->Tf
.Eip
= TrapFrame
->Eip
;
168 KdbTrapFrame
->Tf
.SegCs
= TrapFrame
->SegCs
;
169 KdbTrapFrame
->Tf
.EFlags
= TrapFrame
->EFlags
;
170 KdbTrapFrame
->Tf
.Esp
= KiEspFromTrapFrame(TrapFrame
);
171 KdbTrapFrame
->Tf
.SegSs
= (USHORT
)(KiSsFromTrapFrame(TrapFrame
) & 0xFFFF);
173 KdbTrapFrame
->Cr0
= __readcr0();
174 KdbTrapFrame
->Cr2
= __readcr2();
175 KdbTrapFrame
->Cr3
= __readcr3();
176 KdbTrapFrame
->Cr4
= __readcr4();
178 /* FIXME: copy v86 registers if TrapFrame is a V86 trapframe */
183 KdbpKdbTrapFrameToTrapFrame(
184 PKDB_KTRAP_FRAME KdbTrapFrame
,
186 PKTRAP_FRAME TrapFrame
)
191 *Context
= KdbTrapFrame
->Tf
;
196 TrapFrame
->Dr0
= KdbTrapFrame
->Tf
.Dr0
;
197 TrapFrame
->Dr1
= KdbTrapFrame
->Tf
.Dr1
;
198 TrapFrame
->Dr2
= KdbTrapFrame
->Tf
.Dr2
;
199 TrapFrame
->Dr3
= KdbTrapFrame
->Tf
.Dr3
;
200 TrapFrame
->Dr6
= KdbTrapFrame
->Tf
.Dr6
;
201 TrapFrame
->Dr7
= KdbTrapFrame
->Tf
.Dr7
;
202 TrapFrame
->SegGs
= KdbTrapFrame
->Tf
.SegGs
;
203 TrapFrame
->SegEs
= KdbTrapFrame
->Tf
.SegEs
;
204 TrapFrame
->SegDs
= KdbTrapFrame
->Tf
.SegDs
;
205 TrapFrame
->Edx
= KdbTrapFrame
->Tf
.Edx
;
206 TrapFrame
->Ecx
= KdbTrapFrame
->Tf
.Ecx
;
207 TrapFrame
->Eax
= KdbTrapFrame
->Tf
.Eax
;
208 TrapFrame
->SegFs
= KdbTrapFrame
->Tf
.SegFs
;
209 TrapFrame
->Edi
= KdbTrapFrame
->Tf
.Edi
;
210 TrapFrame
->Esi
= KdbTrapFrame
->Tf
.Esi
;
211 TrapFrame
->Ebx
= KdbTrapFrame
->Tf
.Ebx
;
212 TrapFrame
->Ebp
= KdbTrapFrame
->Tf
.Ebp
;
213 TrapFrame
->Eip
= KdbTrapFrame
->Tf
.Eip
;
214 TrapFrame
->SegCs
= KdbTrapFrame
->Tf
.SegCs
;
215 TrapFrame
->EFlags
= KdbTrapFrame
->Tf
.EFlags
;
216 KiSsToTrapFrame(TrapFrame
, KdbTrapFrame
->Tf
.SegSs
);
217 KiEspToTrapFrame(TrapFrame
, KdbTrapFrame
->Tf
.Esp
);
219 /* FIXME: write cr0, cr2, cr3 and cr4 (not needed atm) */
221 /* FIXME: copy v86 registers if TrapFrame is a V86 trapframe */
226 KdbpKdbTrapFrameFromKernelStack(
228 PKDB_KTRAP_FRAME KdbTrapFrame
)
232 RtlZeroMemory(KdbTrapFrame
, sizeof(KDB_KTRAP_FRAME
));
233 StackPtr
= (ULONG_PTR
*) KernelStack
;
235 KdbTrapFrame
->Tf
.Ebp
= StackPtr
[3];
236 KdbTrapFrame
->Tf
.Edi
= StackPtr
[4];
237 KdbTrapFrame
->Tf
.Esi
= StackPtr
[5];
238 KdbTrapFrame
->Tf
.Ebx
= StackPtr
[6];
239 KdbTrapFrame
->Tf
.Eip
= StackPtr
[7];
240 KdbTrapFrame
->Tf
.Esp
= (ULONG
) (StackPtr
+ 8);
241 KdbTrapFrame
->Tf
.SegSs
= KGDT_R0_DATA
;
242 KdbTrapFrame
->Tf
.SegCs
= KGDT_R0_CODE
;
243 KdbTrapFrame
->Tf
.SegDs
= KGDT_R0_DATA
;
244 KdbTrapFrame
->Tf
.SegEs
= KGDT_R0_DATA
;
245 KdbTrapFrame
->Tf
.SegGs
= KGDT_R0_DATA
;
248 /* FIXME: what about the other registers??? */
251 /*!\brief Overwrites the instruction at \a Address with \a NewInst and stores
252 * the old instruction in *OldInst.
254 * \param Process Process in which's context to overwrite the instruction.
255 * \param Address Address at which to overwrite the instruction.
256 * \param NewInst New instruction (written to \a Address)
257 * \param OldInst Old instruction (read from \a Address)
262 KdbpOverwriteInstruction(
263 IN PEPROCESS Process
,
264 IN ULONG_PTR Address
,
266 OUT PUCHAR OldInst OPTIONAL
)
270 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
273 /* Get the protection for the address. */
274 Protect
= MmGetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
));
276 /* Return if that page isn't present. */
277 if (Protect
& PAGE_NOACCESS
)
279 return STATUS_MEMORY_NOT_ALLOCATED
;
282 /* Attach to the process */
283 if (CurrentProcess
!= Process
)
285 KeStackAttachProcess(&Process
->Pcb
, &ApcState
);
288 /* Make the page writeable if it is read only. */
289 if (Protect
& (PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
))
291 MmSetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
),
292 (Protect
& ~(PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
)) | PAGE_READWRITE
);
295 /* Copy the old instruction back to the caller. */
298 Status
= KdbpSafeReadMemory(OldInst
, (PUCHAR
)Address
, 1);
299 if (!NT_SUCCESS(Status
))
301 if (Protect
& (PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
))
303 MmSetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
), Protect
);
306 /* Detach from process */
307 if (CurrentProcess
!= Process
)
316 /* Copy the new instruction in its place. */
317 Status
= KdbpSafeWriteMemory((PUCHAR
)Address
, &NewInst
, 1);
319 /* Restore the page protection. */
320 if (Protect
& (PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
))
322 MmSetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
), Protect
);
325 /* Detach from process */
326 if (CurrentProcess
!= Process
)
328 KeUnstackDetachProcess(&ApcState
);
334 /*!\brief Checks whether the given instruction can be single stepped or has to be
335 * stepped over using a temporary breakpoint.
337 * \retval TRUE Instruction is a call.
338 * \retval FALSE Instruction is not a call.
341 KdbpShouldStepOverInstruction(
347 if (!NT_SUCCESS(KdbpSafeReadMemory(Mem
, (PVOID
)Eip
, sizeof (Mem
))))
349 KdbpPrint("Couldn't access memory at 0x%p\n", Eip
);
353 /* Check if the current instruction is a call. */
354 while ((i
< sizeof (Mem
)) && (Mem
[i
] == 0x66 || Mem
[i
] == 0x67))
357 if (i
== sizeof (Mem
))
360 if (Mem
[i
] == 0xE8 || Mem
[i
] == 0x9A || Mem
[i
] == 0xF2 || Mem
[i
] == 0xF3 ||
361 (((i
+ 1) < sizeof (Mem
)) && Mem
[i
] == 0xFF && (Mem
[i
+1] & 0x38) == 0x10))
369 /*!\brief Steps over an instruction
371 * If the given instruction should be stepped over, this function inserts a
372 * temporary breakpoint after the instruction and returns TRUE, otherwise it
375 * \retval TRUE Temporary breakpoint set after instruction.
376 * \retval FALSE No breakpoint was set.
379 KdbpStepOverInstruction(
384 if (!KdbpShouldStepOverInstruction(Eip
))
387 InstLen
= KdbpGetInstLength(Eip
);
391 if (!NT_SUCCESS(KdbpInsertBreakPoint(Eip
+ InstLen
, KdbBreakPointTemporary
, 0, 0, NULL
, FALSE
, NULL
)))
397 /*!\brief Steps into an instruction (interrupts)
399 * If the given instruction should be stepped into, this function inserts a
400 * temporary breakpoint at the target instruction and returns TRUE, otherwise it
403 * \retval TRUE Temporary breakpoint set at target instruction.
404 * \retval FALSE No breakpoint was set.
407 KdbpStepIntoInstruction(
410 KDESCRIPTOR Idtr
= {0};
417 if (!NT_SUCCESS(KdbpSafeReadMemory(Mem
, (PVOID
)Eip
, sizeof (Mem
))))
419 /*KdbpPrint("Couldn't access memory at 0x%p\n", Eip);*/
423 /* Check for INT instruction */
424 /* FIXME: Check for iret */
427 else if (Mem
[0] == 0xcd)
429 else if (Mem
[0] == 0xce && KdbCurrentTrapFrame
->Tf
.EFlags
& (1<<11)) /* 1 << 11 is the overflow flag */
434 if (IntVect
< 32) /* We should be informed about interrupts < 32 by the kernel, no need to breakpoint them */
439 /* Read the interrupt descriptor table register */
441 if (IntVect
>= (Idtr
.Limit
+ 1) / 8)
443 /*KdbpPrint("IDT does not contain interrupt vector %d\n.", IntVect);*/
447 /* Get the interrupt descriptor */
448 if (!NT_SUCCESS(KdbpSafeReadMemory(IntDesc
, (PVOID
)(ULONG_PTR
)(Idtr
.Base
+ (IntVect
* 8)), sizeof (IntDesc
))))
450 /*KdbpPrint("Couldn't access memory at 0x%p\n", (ULONG_PTR)Idtr.Base + (IntVect * 8));*/
454 /* Check descriptor and get target eip (16 bit interrupt/trap gates not supported) */
455 if ((IntDesc
[1] & (1 << 15)) == 0) /* not present */
459 if ((IntDesc
[1] & 0x1f00) == 0x0500) /* Task gate */
461 /* FIXME: Task gates not supported */
464 else if (((IntDesc
[1] & 0x1fe0) == 0x0e00) || /* 32 bit Interrupt gate */
465 ((IntDesc
[1] & 0x1fe0) == 0x0f00)) /* 32 bit Trap gate */
467 /* FIXME: Should the segment selector of the interrupt gate be checked? */
468 TargetEip
= (IntDesc
[1] & 0xffff0000) | (IntDesc
[0] & 0x0000ffff);
475 /* Insert breakpoint */
476 if (!NT_SUCCESS(KdbpInsertBreakPoint(TargetEip
, KdbBreakPointTemporary
, 0, 0, NULL
, FALSE
, NULL
)))
482 /*!\brief Gets the number of the next breakpoint >= Start.
484 * \param Start Breakpoint number to start searching at. -1 if no more breakpoints are found.
486 * \returns Breakpoint number (-1 if no more breakpoints are found)
489 KdbpGetNextBreakPointNr(
490 IN ULONG Start OPTIONAL
)
492 for (; Start
< RTL_NUMBER_OF(KdbBreakPoints
); Start
++)
494 if (KdbBreakPoints
[Start
].Type
!= KdbBreakPointNone
)
501 /*!\brief Returns information of the specified breakpoint.
503 * \param BreakPointNr Number of the breakpoint to return information of.
504 * \param Address Receives the address of the breakpoint.
505 * \param Type Receives the type of the breakpoint (hardware or software)
506 * \param Size Size - for memory breakpoints.
507 * \param AccessType Access type - for hardware breakpoints.
508 * \param DebugReg Debug register - for enabled hardware breakpoints.
509 * \param Enabled Whether the breakpoint is enabled or not.
510 * \param Process The owning process of the breakpoint.
511 * \param ConditionExpression The expression which was given as condition for the bp.
513 * \returns NULL on failure, pointer to a KDB_BREAKPOINT struct on success.
516 KdbpGetBreakPointInfo(
517 IN ULONG BreakPointNr
,
518 OUT ULONG_PTR
*Address OPTIONAL
,
519 OUT KDB_BREAKPOINT_TYPE
*Type OPTIONAL
,
520 OUT UCHAR
*Size OPTIONAL
,
521 OUT KDB_ACCESS_TYPE
*AccessType OPTIONAL
,
522 OUT UCHAR
*DebugReg OPTIONAL
,
523 OUT BOOLEAN
*Enabled OPTIONAL
,
524 OUT BOOLEAN
*Global OPTIONAL
,
525 OUT PEPROCESS
*Process OPTIONAL
,
526 OUT PCHAR
*ConditionExpression OPTIONAL
)
530 if (BreakPointNr
>= RTL_NUMBER_OF(KdbBreakPoints
) ||
531 KdbBreakPoints
[BreakPointNr
].Type
== KdbBreakPointNone
)
536 bp
= KdbBreakPoints
+ BreakPointNr
;
538 *Address
= bp
->Address
;
543 if (bp
->Type
== KdbBreakPointHardware
)
546 *Size
= bp
->Data
.Hw
.Size
;
549 *AccessType
= bp
->Data
.Hw
.AccessType
;
551 if (DebugReg
&& bp
->Enabled
)
552 *DebugReg
= bp
->Data
.Hw
.DebugReg
;
556 *Enabled
= bp
->Enabled
;
559 *Global
= bp
->Global
;
562 *Process
= bp
->Process
;
564 if (ConditionExpression
)
565 *ConditionExpression
= bp
->ConditionExpression
;
570 /*!\brief Inserts a breakpoint into the breakpoint array.
572 * The \a Process of the breakpoint is set to \a KdbCurrentProcess
574 * \param Address Address at which to set the breakpoint.
575 * \param Type Type of breakpoint (hardware or software)
576 * \param Size Size of breakpoint (for hardware/memory breakpoints)
577 * \param AccessType Access type (for hardware breakpoins)
578 * \param ConditionExpression Expression which must evaluate to true for conditional breakpoints.
579 * \param Global Wether the breakpoint is global or local to a process.
580 * \param BreakPointNumber Receives the breakpoint number on success
585 KdbpInsertBreakPoint(
586 IN ULONG_PTR Address
,
587 IN KDB_BREAKPOINT_TYPE Type
,
588 IN UCHAR Size OPTIONAL
,
589 IN KDB_ACCESS_TYPE AccessType OPTIONAL
,
590 IN PCHAR ConditionExpression OPTIONAL
,
592 OUT PLONG BreakPointNr OPTIONAL
)
596 PCHAR ConditionExpressionDup
;
600 ASSERT(Type
!= KdbBreakPointNone
);
602 if (Type
== KdbBreakPointHardware
)
604 if ((Address
% Size
) != 0)
606 KdbpPrint("Address (0x%p) must be aligned to a multiple of the size (%d)\n", Address
, Size
);
607 return STATUS_UNSUCCESSFUL
;
610 if (AccessType
== KdbAccessExec
&& Size
!= 1)
612 KdbpPrint("Size must be 1 for execution breakpoints.\n");
613 return STATUS_UNSUCCESSFUL
;
617 if (KdbBreakPointCount
== KDB_MAXIMUM_BREAKPOINT_COUNT
)
619 return STATUS_UNSUCCESSFUL
;
622 /* Parse conditon expression string and duplicate it */
623 if (ConditionExpression
)
625 Condition
= KdbpRpnParseExpression(ConditionExpression
, &ErrOffset
, ErrMsg
);
629 KdbpPrint("Couldn't parse expression: %s at character %d\n", ErrMsg
, ErrOffset
);
631 KdbpPrint("Couldn't parse expression: %s", ErrMsg
);
633 return STATUS_UNSUCCESSFUL
;
636 i
= strlen(ConditionExpression
) + 1;
637 ConditionExpressionDup
= ExAllocatePoolWithTag(NonPagedPool
, i
, TAG_KDBG
);
638 RtlCopyMemory(ConditionExpressionDup
, ConditionExpression
, i
);
643 ConditionExpressionDup
= NULL
;
646 /* Find unused breakpoint */
647 if (Type
== KdbBreakPointTemporary
)
649 for (i
= RTL_NUMBER_OF(KdbBreakPoints
) - 1; i
>= 0; i
--)
651 if (KdbBreakPoints
[i
].Type
== KdbBreakPointNone
)
657 for (i
= 0; i
< (LONG
)RTL_NUMBER_OF(KdbBreakPoints
); i
++)
659 if (KdbBreakPoints
[i
].Type
== KdbBreakPointNone
)
664 ASSERT(i
< (LONG
)RTL_NUMBER_OF(KdbBreakPoints
));
666 /* Set the breakpoint */
667 ASSERT(KdbCurrentProcess
);
668 KdbBreakPoints
[i
].Type
= Type
;
669 KdbBreakPoints
[i
].Address
= Address
;
670 KdbBreakPoints
[i
].Enabled
= FALSE
;
671 KdbBreakPoints
[i
].Global
= Global
;
672 KdbBreakPoints
[i
].Process
= KdbCurrentProcess
;
673 KdbBreakPoints
[i
].ConditionExpression
= ConditionExpressionDup
;
674 KdbBreakPoints
[i
].Condition
= Condition
;
676 if (Type
== KdbBreakPointHardware
)
678 KdbBreakPoints
[i
].Data
.Hw
.Size
= Size
;
679 KdbBreakPoints
[i
].Data
.Hw
.AccessType
= AccessType
;
682 KdbBreakPointCount
++;
684 if (Type
!= KdbBreakPointTemporary
)
685 KdbpPrint("Breakpoint %d inserted.\n", i
);
687 /* Try to enable the breakpoint */
688 KdbpEnableBreakPoint(i
, NULL
);
690 /* Return the breakpoint number */
694 return STATUS_SUCCESS
;
697 /*!\brief Deletes a breakpoint
699 * \param BreakPointNr Number of the breakpoint to delete. Can be -1
700 * \param BreakPoint Breakpoint to delete. Can be NULL.
702 * \retval TRUE Success.
703 * \retval FALSE Failure (invalid breakpoint number)
706 KdbpDeleteBreakPoint(
707 IN LONG BreakPointNr OPTIONAL
,
708 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL
)
710 if (BreakPointNr
< 0)
713 BreakPointNr
= BreakPoint
- KdbBreakPoints
;
716 if (BreakPointNr
< 0 || BreakPointNr
>= KDB_MAXIMUM_BREAKPOINT_COUNT
)
718 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
724 BreakPoint
= KdbBreakPoints
+ BreakPointNr
;
727 if (BreakPoint
->Type
== KdbBreakPointNone
)
729 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
733 if (BreakPoint
->Enabled
&& !KdbpDisableBreakPoint(-1, BreakPoint
))
736 if (BreakPoint
->Type
!= KdbBreakPointTemporary
)
737 KdbpPrint("Breakpoint %d deleted.\n", BreakPointNr
);
739 BreakPoint
->Type
= KdbBreakPointNone
;
740 KdbBreakPointCount
--;
745 /*!\brief Checks if the breakpoint was set by the debugger
747 * Tries to find a breakpoint in the breakpoint array which caused
748 * the debug exception to happen.
750 * \param ExpNr Exception Number (1 or 3)
751 * \param TrapFrame Exception trapframe
753 * \returns Breakpoint number, -1 on error.
756 KdbpIsBreakPointOurs(
757 IN NTSTATUS ExceptionCode
,
758 IN PKTRAP_FRAME TrapFrame
)
761 ASSERT(ExceptionCode
== STATUS_SINGLE_STEP
|| ExceptionCode
== STATUS_BREAKPOINT
);
763 if (ExceptionCode
== STATUS_BREAKPOINT
) /* Software interrupt */
765 ULONG_PTR BpEip
= (ULONG_PTR
)TrapFrame
->Eip
- 1; /* Get EIP of INT3 instruction */
766 for (i
= 0; i
< KdbSwBreakPointCount
; i
++)
768 ASSERT((KdbSwBreakPoints
[i
]->Type
== KdbBreakPointSoftware
||
769 KdbSwBreakPoints
[i
]->Type
== KdbBreakPointTemporary
));
770 ASSERT(KdbSwBreakPoints
[i
]->Enabled
);
772 if (KdbSwBreakPoints
[i
]->Address
== BpEip
)
774 return KdbSwBreakPoints
[i
] - KdbBreakPoints
;
778 else if (ExceptionCode
== STATUS_SINGLE_STEP
) /* Hardware interrupt */
782 for (i
= 0; i
< KdbHwBreakPointCount
; i
++)
784 ASSERT(KdbHwBreakPoints
[i
]->Type
== KdbBreakPointHardware
&&
785 KdbHwBreakPoints
[i
]->Enabled
);
786 DebugReg
= KdbHwBreakPoints
[i
]->Data
.Hw
.DebugReg
;
788 if ((TrapFrame
->Dr6
& (1 << DebugReg
)) != 0)
790 return KdbHwBreakPoints
[i
] - KdbBreakPoints
;
798 /*!\brief Enables a breakpoint.
800 * \param BreakPointNr Number of the breakpoint to enable Can be -1.
801 * \param BreakPoint Breakpoint to enable. Can be NULL.
803 * \retval TRUE Success.
804 * \retval FALSE Failure.
806 * \sa KdbpDisableBreakPoint
809 KdbpEnableBreakPoint(
810 IN LONG BreakPointNr OPTIONAL
,
811 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL
)
817 if (BreakPointNr
< 0)
820 BreakPointNr
= BreakPoint
- KdbBreakPoints
;
823 if (BreakPointNr
< 0 || BreakPointNr
>= KDB_MAXIMUM_BREAKPOINT_COUNT
)
825 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
831 BreakPoint
= KdbBreakPoints
+ BreakPointNr
;
834 if (BreakPoint
->Type
== KdbBreakPointNone
)
836 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
840 if (BreakPoint
->Enabled
)
842 KdbpPrint("Breakpoint %d is already enabled.\n", BreakPointNr
);
846 if (BreakPoint
->Type
== KdbBreakPointSoftware
||
847 BreakPoint
->Type
== KdbBreakPointTemporary
)
849 if (KdbSwBreakPointCount
>= KDB_MAXIMUM_SW_BREAKPOINT_COUNT
)
851 KdbpPrint("Maximum number of SW breakpoints (%d) used. "
852 "Disable another breakpoint in order to enable this one.\n",
853 KDB_MAXIMUM_SW_BREAKPOINT_COUNT
);
857 Status
= KdbpOverwriteInstruction(BreakPoint
->Process
, BreakPoint
->Address
,
858 0xCC, &BreakPoint
->Data
.SavedInstruction
);
859 if (!NT_SUCCESS(Status
))
861 KdbpPrint("Couldn't access memory at 0x%p\n", BreakPoint
->Address
);
865 KdbSwBreakPoints
[KdbSwBreakPointCount
++] = BreakPoint
;
869 if (BreakPoint
->Data
.Hw
.AccessType
== KdbAccessExec
)
870 ASSERT(BreakPoint
->Data
.Hw
.Size
== 1);
872 ASSERT((BreakPoint
->Address
% BreakPoint
->Data
.Hw
.Size
) == 0);
874 if (KdbHwBreakPointCount
>= KDB_MAXIMUM_HW_BREAKPOINT_COUNT
)
876 KdbpPrint("Maximum number of HW breakpoints (%d) already used. "
877 "Disable another breakpoint in order to enable this one.\n",
878 KDB_MAXIMUM_HW_BREAKPOINT_COUNT
);
883 /* Find unused hw breakpoint */
884 ASSERT(KDB_MAXIMUM_HW_BREAKPOINT_COUNT
== 4);
885 for (i
= 0; i
< KDB_MAXIMUM_HW_BREAKPOINT_COUNT
; i
++)
887 if ((KdbTrapFrame
.Tf
.Dr7
& (0x3 << (i
* 2))) == 0)
891 ASSERT(i
< KDB_MAXIMUM_HW_BREAKPOINT_COUNT
);
893 /* Set the breakpoint address. */
897 KdbTrapFrame
.Tf
.Dr0
= BreakPoint
->Address
;
900 KdbTrapFrame
.Tf
.Dr1
= BreakPoint
->Address
;
903 KdbTrapFrame
.Tf
.Dr2
= BreakPoint
->Address
;
906 KdbTrapFrame
.Tf
.Dr3
= BreakPoint
->Address
;
910 /* Enable the global breakpoint */
911 KdbTrapFrame
.Tf
.Dr7
|= (0x2 << (i
* 2));
913 /* Enable the exact match bits. */
914 KdbTrapFrame
.Tf
.Dr7
|= 0x00000300;
916 /* Clear existing state. */
917 KdbTrapFrame
.Tf
.Dr7
&= ~(0xF << (16 + (i
* 4)));
919 /* Set the breakpoint type. */
920 switch (BreakPoint
->Data
.Hw
.AccessType
)
929 case KdbAccessReadWrite
:
938 KdbTrapFrame
.Tf
.Dr7
|= (ul
<< (16 + (i
* 4)));
940 /* Set the breakpoint length. */
941 KdbTrapFrame
.Tf
.Dr7
|= ((BreakPoint
->Data
.Hw
.Size
- 1) << (18 + (i
* 4)));
943 /* Update KdbCurrentTrapFrame - values are taken from there by the CLI */
944 if (&KdbTrapFrame
!= KdbCurrentTrapFrame
)
946 KdbCurrentTrapFrame
->Tf
.Dr0
= KdbTrapFrame
.Tf
.Dr0
;
947 KdbCurrentTrapFrame
->Tf
.Dr1
= KdbTrapFrame
.Tf
.Dr1
;
948 KdbCurrentTrapFrame
->Tf
.Dr2
= KdbTrapFrame
.Tf
.Dr2
;
949 KdbCurrentTrapFrame
->Tf
.Dr3
= KdbTrapFrame
.Tf
.Dr3
;
950 KdbCurrentTrapFrame
->Tf
.Dr6
= KdbTrapFrame
.Tf
.Dr6
;
951 KdbCurrentTrapFrame
->Tf
.Dr7
= KdbTrapFrame
.Tf
.Dr7
;
954 BreakPoint
->Data
.Hw
.DebugReg
= i
;
955 KdbHwBreakPoints
[KdbHwBreakPointCount
++] = BreakPoint
;
958 BreakPoint
->Enabled
= TRUE
;
959 if (BreakPoint
->Type
!= KdbBreakPointTemporary
)
960 KdbpPrint("Breakpoint %d enabled.\n", BreakPointNr
);
965 /*!\brief Disables a breakpoint.
967 * \param BreakPointNr Number of the breakpoint to disable. Can be -1
968 * \param BreakPoint Breakpoint to disable. Can be NULL.
970 * \retval TRUE Success.
971 * \retval FALSE Failure.
973 * \sa KdbpEnableBreakPoint
976 KdbpDisableBreakPoint(
977 IN LONG BreakPointNr OPTIONAL
,
978 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL
)
983 if (BreakPointNr
< 0)
986 BreakPointNr
= BreakPoint
- KdbBreakPoints
;
989 if (BreakPointNr
< 0 || BreakPointNr
>= KDB_MAXIMUM_BREAKPOINT_COUNT
)
991 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
997 BreakPoint
= KdbBreakPoints
+ BreakPointNr
;
1000 if (BreakPoint
->Type
== KdbBreakPointNone
)
1002 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
1006 if (BreakPoint
->Enabled
== FALSE
)
1008 KdbpPrint("Breakpoint %d is not enabled.\n", BreakPointNr
);
1012 if (BreakPoint
->Type
== KdbBreakPointSoftware
||
1013 BreakPoint
->Type
== KdbBreakPointTemporary
)
1015 ASSERT(KdbSwBreakPointCount
> 0);
1016 Status
= KdbpOverwriteInstruction(BreakPoint
->Process
, BreakPoint
->Address
,
1017 BreakPoint
->Data
.SavedInstruction
, NULL
);
1019 if (!NT_SUCCESS(Status
))
1021 KdbpPrint("Couldn't restore original instruction.\n");
1025 for (i
= 0; i
< KdbSwBreakPointCount
; i
++)
1027 if (KdbSwBreakPoints
[i
] == BreakPoint
)
1029 KdbSwBreakPoints
[i
] = KdbSwBreakPoints
[--KdbSwBreakPointCount
];
1030 i
= -1; /* if the last breakpoint is disabled dont break with i >= KdbSwBreakPointCount */
1035 if (i
!= MAXULONG
) /* not found */
1040 ASSERT(BreakPoint
->Type
== KdbBreakPointHardware
);
1042 /* Clear the breakpoint. */
1043 KdbTrapFrame
.Tf
.Dr7
&= ~(0x3 << (BreakPoint
->Data
.Hw
.DebugReg
* 2));
1044 if ((KdbTrapFrame
.Tf
.Dr7
& 0xFF) == 0)
1046 /* If no breakpoints are enabled then clear the exact match flags. */
1047 KdbTrapFrame
.Tf
.Dr7
&= 0xFFFFFCFF;
1050 for (i
= 0; i
< KdbHwBreakPointCount
; i
++)
1052 if (KdbHwBreakPoints
[i
] == BreakPoint
)
1054 KdbHwBreakPoints
[i
] = KdbHwBreakPoints
[--KdbHwBreakPointCount
];
1055 i
= -1; /* if the last breakpoint is disabled dont break with i >= KdbHwBreakPointCount */
1060 if (i
!= MAXULONG
) /* not found */
1064 BreakPoint
->Enabled
= FALSE
;
1065 if (BreakPoint
->Type
!= KdbBreakPointTemporary
)
1066 KdbpPrint("Breakpoint %d disabled.\n", BreakPointNr
);
1071 /*!\brief Gets the first or last chance enter-condition for exception nr. \a ExceptionNr
1073 * \param ExceptionNr Number of the exception to get condition of.
1074 * \param FirstChance Whether to get first or last chance condition.
1075 * \param Condition Receives the condition setting.
1077 * \retval TRUE Success.
1078 * \retval FALSE Failure (invalid exception nr)
1081 KdbpGetEnterCondition(
1082 IN LONG ExceptionNr
,
1083 IN BOOLEAN FirstChance
,
1084 OUT KDB_ENTER_CONDITION
*Condition
)
1086 if (ExceptionNr
>= (LONG
)RTL_NUMBER_OF(KdbEnterConditions
))
1089 *Condition
= KdbEnterConditions
[ExceptionNr
][FirstChance
? 0 : 1];
1093 /*!\brief Sets the first or last chance enter-condition for exception nr. \a ExceptionNr
1095 * \param ExceptionNr Number of the exception to set condition of (-1 for all)
1096 * \param FirstChance Whether to set first or last chance condition.
1097 * \param Condition The new condition setting.
1099 * \retval TRUE Success.
1100 * \retval FALSE Failure (invalid exception nr)
1103 KdbpSetEnterCondition(
1104 IN LONG ExceptionNr
,
1105 IN BOOLEAN FirstChance
,
1106 IN KDB_ENTER_CONDITION Condition
)
1108 if (ExceptionNr
< 0)
1110 for (ExceptionNr
= 0; ExceptionNr
< (LONG
)RTL_NUMBER_OF(KdbEnterConditions
); ExceptionNr
++)
1112 if (ExceptionNr
== 1 || ExceptionNr
== 8 ||
1113 ExceptionNr
== 9 || ExceptionNr
== 15) /* Reserved exceptions */
1118 KdbEnterConditions
[ExceptionNr
][FirstChance
? 0 : 1] = Condition
;
1123 if (ExceptionNr
>= (LONG
)RTL_NUMBER_OF(KdbEnterConditions
) ||
1124 ExceptionNr
== 1 || ExceptionNr
== 8 || /* Do not allow changing of the debug */
1125 ExceptionNr
== 9 || ExceptionNr
== 15) /* trap or reserved exceptions */
1130 KdbEnterConditions
[ExceptionNr
][FirstChance
? 0 : 1] = Condition
;
1136 /*!\brief Switches to another thread context
1138 * \param ThreadId Id of the thread to switch to.
1140 * \retval TRUE Success.
1141 * \retval FALSE Failure (i.e. invalid thread id)
1147 PETHREAD Thread
= NULL
;
1150 /* Get a pointer to the thread */
1151 if (!NT_SUCCESS(PsLookupThreadByThreadId(ThreadId
, &Thread
)))
1153 KdbpPrint("Invalid thread id: 0x%08x\n", (ULONG_PTR
)ThreadId
);
1156 Process
= Thread
->ThreadsProcess
;
1158 if (KeIsExecutingDpc() && Process
!= KdbCurrentProcess
)
1160 KdbpPrint("Cannot attach to thread within another process while executing a DPC.\n");
1161 ObDereferenceObject(Thread
);
1165 /* Save the current thread's context (if we previously attached to a thread) */
1166 if (KdbCurrentThread
!= KdbOriginalThread
)
1168 ASSERT(KdbCurrentTrapFrame
== &KdbThreadTrapFrame
);
1169 /* Actually, we can't save the context, there's no guarantee that there was a trap frame */
1173 ASSERT(KdbCurrentTrapFrame
== &KdbTrapFrame
);
1176 /* Switch to the thread's context */
1177 if (Thread
!= KdbOriginalThread
)
1179 /* The thread we're attaching to isn't the thread on which we entered
1180 * kdb and so the thread we're attaching to is not running. There
1181 * is no guarantee that it actually has a trap frame. So we have to
1182 * peek directly at the registers which were saved on the stack when the
1183 * thread was preempted in the scheduler */
1184 KdbpKdbTrapFrameFromKernelStack(Thread
->Tcb
.KernelStack
,
1185 &KdbThreadTrapFrame
);
1186 KdbCurrentTrapFrame
= &KdbThreadTrapFrame
;
1188 else /* Switching back to original thread */
1190 KdbCurrentTrapFrame
= &KdbTrapFrame
;
1192 KdbCurrentThread
= Thread
;
1194 /* Attach to the thread's process */
1195 ASSERT(KdbCurrentProcess
== PsGetCurrentProcess());
1196 if (KdbCurrentProcess
!= Process
)
1198 if (KdbCurrentProcess
!= KdbOriginalProcess
) /* detach from previously attached process */
1200 KeUnstackDetachProcess(&KdbApcState
);
1203 if (KdbOriginalProcess
!= Process
)
1205 KeStackAttachProcess(&Process
->Pcb
, &KdbApcState
);
1208 KdbCurrentProcess
= Process
;
1211 ObDereferenceObject(Thread
);
1215 /*!\brief Switches to another process/thread context
1217 * This function switches to the first thread in the specified process.
1219 * \param ProcessId Id of the process to switch to.
1221 * \retval TRUE Success.
1222 * \retval FALSE Failure (i.e. invalid process id)
1225 KdbpAttachToProcess(
1228 PEPROCESS Process
= NULL
;
1232 /* Get a pointer to the process */
1233 if (!NT_SUCCESS(PsLookupProcessByProcessId(ProcessId
, &Process
)))
1235 KdbpPrint("Invalid process id: 0x%08x\n", (ULONG_PTR
)ProcessId
);
1239 Entry
= Process
->ThreadListHead
.Flink
;
1240 ObDereferenceObject(Process
);
1241 if (Entry
== &KdbCurrentProcess
->ThreadListHead
)
1243 KdbpPrint("No threads in process 0x%p, cannot attach to process!\n", ProcessId
);
1247 Thread
= CONTAINING_RECORD(Entry
, ETHREAD
, ThreadListEntry
);
1249 return KdbpAttachToThread(Thread
->Cid
.UniqueThread
);
1252 /*!\brief Calls the main loop ...
1255 KdbpCallMainLoop(VOID
)
1257 KdbpCliMainLoop(KdbEnteredOnSingleStep
);
1260 /*!\brief Internal function to enter KDB.
1262 * Disables interrupts, releases display ownership, ...
1265 KdbpInternalEnter(VOID
)
1268 PVOID SavedInitialStack
, SavedStackBase
, SavedKernelStack
;
1269 ULONG SavedStackLimit
;
1273 if (KdpDebugMode
.Screen
&&
1274 InbvIsBootDriverInstalled() &&
1275 !InbvCheckDisplayOwnership())
1277 /* Acquire ownership and reset the display */
1278 InbvAcquireDisplayOwnership();
1281 /* Display debugger prompt */
1282 InbvSolidColorFill(0, 0, 639, 479, 0);
1283 InbvSetTextColor(15);
1284 InbvInstallDisplayStringFilter(NULL
);
1285 InbvEnableDisplayString(TRUE
);
1286 InbvSetScrollRegion(0, 0, 639, 479);
1289 /* Call the interface's main loop on a different stack */
1290 Thread
= PsGetCurrentThread();
1291 SavedInitialStack
= Thread
->Tcb
.InitialStack
;
1292 SavedStackBase
= Thread
->Tcb
.StackBase
;
1293 SavedStackLimit
= Thread
->Tcb
.StackLimit
;
1294 SavedKernelStack
= Thread
->Tcb
.KernelStack
;
1295 Thread
->Tcb
.InitialStack
= Thread
->Tcb
.StackBase
= (char*)KdbStack
+ KDB_STACK_SIZE
;
1296 Thread
->Tcb
.StackLimit
= (ULONG_PTR
)KdbStack
;
1297 Thread
->Tcb
.KernelStack
= (char*)KdbStack
+ KDB_STACK_SIZE
;
1299 /*KdbpPrint("Switching to KDB stack 0x%08x-0x%08x (Current Stack is 0x%08x)\n", Thread->Tcb.StackLimit, Thread->Tcb.StackBase, Esp);*/
1301 KdbpStackSwitchAndCall(KdbStack
+ KDB_STACK_SIZE
- sizeof(ULONG
), KdbpCallMainLoop
);
1303 Thread
->Tcb
.InitialStack
= SavedInitialStack
;
1304 Thread
->Tcb
.StackBase
= SavedStackBase
;
1305 Thread
->Tcb
.StackLimit
= SavedStackLimit
;
1306 Thread
->Tcb
.KernelStack
= SavedKernelStack
;
1311 KdbpGetExceptionNumberFromStatus(
1312 IN NTSTATUS ExceptionCode
)
1316 switch (ExceptionCode
)
1318 case STATUS_INTEGER_DIVIDE_BY_ZERO
:
1321 case STATUS_SINGLE_STEP
:
1324 case STATUS_BREAKPOINT
:
1327 case STATUS_INTEGER_OVERFLOW
:
1330 case STATUS_ARRAY_BOUNDS_EXCEEDED
:
1333 case STATUS_ILLEGAL_INSTRUCTION
:
1336 case STATUS_FLOAT_INVALID_OPERATION
:
1339 case STATUS_STACK_OVERFLOW
:
1342 case STATUS_ACCESS_VIOLATION
:
1345 case STATUS_DATATYPE_MISALIGNMENT
:
1348 case STATUS_FLOAT_MULTIPLE_TRAPS
:
1351 case STATUS_ASSERTION_FAILURE
:
1356 Ret
= RTL_NUMBER_OF(KdbEnterConditions
) - 1;
1363 /*!\brief KDB Exception filter
1365 * Called by the exception dispatcher.
1367 * \param ExceptionRecord Unused.
1368 * \param PreviousMode UserMode if the exception was raised from umode, otherwise KernelMode.
1369 * \param Context Context, IN/OUT parameter.
1370 * \param TrapFrame Exception TrapFrame.
1371 * \param FirstChance TRUE when called before exception frames were serached,
1372 * FALSE for the second call.
1374 * \returns KD_CONTINUE_TYPE
1377 KdbEnterDebuggerException(
1378 IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL
,
1379 IN KPROCESSOR_MODE PreviousMode
,
1380 IN PCONTEXT Context
,
1381 IN OUT PKTRAP_FRAME InitialTrapFrame
,
1382 IN BOOLEAN FirstChance
)
1384 PKTRAP_FRAME TrapFrame
= InitialTrapFrame
;
1385 KDB_ENTER_CONDITION EnterCondition
;
1386 KD_CONTINUE_TYPE ContinueType
= kdHandleException
;
1387 PKDB_BREAKPOINT BreakPoint
;
1390 BOOLEAN Resume
= FALSE
;
1391 BOOLEAN EnterConditionMet
= TRUE
;
1394 NTSTATUS ExceptionCode
;
1396 ExceptionCode
= (ExceptionRecord
? ExceptionRecord
->ExceptionCode
: STATUS_BREAKPOINT
);
1398 KdbCurrentProcess
= PsGetCurrentProcess();
1400 /* Set continue type to kdContinue for single steps and breakpoints */
1401 if (ExceptionCode
== STATUS_SINGLE_STEP
||
1402 ExceptionCode
== STATUS_BREAKPOINT
||
1403 ExceptionCode
== STATUS_ASSERTION_FAILURE
)
1405 ContinueType
= kdContinue
;
1408 /* Check if we should handle the exception. */
1409 /* FIXME - won't get all exceptions here :( */
1410 ExpNr
= KdbpGetExceptionNumberFromStatus(ExceptionCode
);
1411 EnterCondition
= KdbEnterConditions
[ExpNr
][FirstChance
? 0 : 1];
1412 if (EnterCondition
== KdbDoNotEnter
||
1413 (EnterCondition
== KdbEnterFromUmode
&& PreviousMode
== KernelMode
) ||
1414 (EnterCondition
== KdbEnterFromKmode
&& PreviousMode
!= KernelMode
))
1416 EnterConditionMet
= FALSE
;
1419 /* If we stopped on one of our breakpoints then let the user know. */
1420 KdbLastBreakPointNr
= -1;
1421 KdbEnteredOnSingleStep
= FALSE
;
1423 if (FirstChance
&& (ExceptionCode
== STATUS_SINGLE_STEP
|| ExceptionCode
== STATUS_BREAKPOINT
) &&
1424 (KdbLastBreakPointNr
= KdbpIsBreakPointOurs(ExceptionCode
, TrapFrame
)) >= 0)
1426 BreakPoint
= KdbBreakPoints
+ KdbLastBreakPointNr
;
1428 if (ExceptionCode
== STATUS_BREAKPOINT
)
1430 /* ... and restore the original instruction. */
1431 if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess
, BreakPoint
->Address
,
1432 BreakPoint
->Data
.SavedInstruction
, NULL
)))
1434 KdbpPrint("Couldn't restore original instruction after INT3! Cannot continue execution.\n");
1435 KeBugCheck(0); // FIXME: Proper bugcode!
1438 /* Also since we are past the int3 now, decrement EIP in the
1439 TrapFrame. This is only needed because KDBG insists on working
1440 with the TrapFrame instead of with the Context, as it is supposed
1441 to do. The context has already EIP point to the int3, since
1442 KiDispatchException accounts for that. Whatever we do here with
1443 the TrapFrame does not matter anyway, since KiDispatchException
1444 will overwrite it with the values from the Context! */
1448 if ((BreakPoint
->Type
== KdbBreakPointHardware
) &&
1449 (BreakPoint
->Data
.Hw
.AccessType
== KdbAccessExec
))
1451 Resume
= TRUE
; /* Set the resume flag when continuing execution */
1455 * When a temporary breakpoint is hit we have to make sure that we are
1456 * in the same context in which it was set, otherwise it could happen
1457 * that another process/thread hits it before and it gets deleted.
1459 else if (BreakPoint
->Type
== KdbBreakPointTemporary
&&
1460 BreakPoint
->Process
== KdbCurrentProcess
)
1462 ASSERT((TrapFrame
->EFlags
& EFLAGS_TF
) == 0);
1464 /* Delete the temporary breakpoint which was used to step over or into the instruction. */
1465 KdbpDeleteBreakPoint(-1, BreakPoint
);
1467 if (--KdbNumSingleSteps
> 0)
1469 if ((KdbSingleStepOver
&& !KdbpStepOverInstruction(TrapFrame
->Eip
)) ||
1470 (!KdbSingleStepOver
&& !KdbpStepIntoInstruction(TrapFrame
->Eip
)))
1472 Context
->EFlags
|= EFLAGS_TF
;
1475 goto continue_execution
; /* return */
1478 KdbEnteredOnSingleStep
= TRUE
;
1482 * If we hit a breakpoint set by the debugger we set the single step flag,
1483 * ignore the next single step and reenable the breakpoint.
1485 else if (BreakPoint
->Type
== KdbBreakPointSoftware
||
1486 BreakPoint
->Type
== KdbBreakPointTemporary
)
1488 ASSERT(ExceptionCode
== STATUS_BREAKPOINT
);
1489 Context
->EFlags
|= EFLAGS_TF
;
1490 KdbBreakPointToReenable
= BreakPoint
;
1493 /* Make sure that the breakpoint should be triggered in this context */
1494 if (!BreakPoint
->Global
&& BreakPoint
->Process
!= KdbCurrentProcess
)
1496 goto continue_execution
; /* return */
1499 /* Check if the condition for the breakpoint is met. */
1500 if (BreakPoint
->Condition
)
1502 /* Setup the KDB trap frame */
1503 KdbpTrapFrameToKdbTrapFrame(Context
, InitialTrapFrame
, &KdbTrapFrame
);
1506 if (!KdbpRpnEvaluateParsedExpression(BreakPoint
->Condition
, &KdbTrapFrame
, &ull
, NULL
, NULL
))
1508 /* FIXME: Print warning? */
1510 else if (ull
== 0) /* condition is not met */
1512 goto continue_execution
; /* return */
1516 if (BreakPoint
->Type
== KdbBreakPointSoftware
)
1518 KdbpPrint("\nEntered debugger on breakpoint #%d: EXEC 0x%04x:0x%08x\n",
1519 KdbLastBreakPointNr
, TrapFrame
->SegCs
& 0xffff, TrapFrame
->Eip
);
1521 else if (BreakPoint
->Type
== KdbBreakPointHardware
)
1523 KdbpPrint("\nEntered debugger on breakpoint #%d: %s 0x%08x\n",
1524 KdbLastBreakPointNr
,
1525 (BreakPoint
->Data
.Hw
.AccessType
== KdbAccessRead
) ? "READ" :
1526 ((BreakPoint
->Data
.Hw
.AccessType
== KdbAccessWrite
) ? "WRITE" :
1527 ((BreakPoint
->Data
.Hw
.AccessType
== KdbAccessReadWrite
) ? "RDWR" : "EXEC")),
1528 BreakPoint
->Address
);
1531 else if (ExceptionCode
== STATUS_SINGLE_STEP
)
1533 /* Silently ignore a debugger initiated single step. */
1534 if ((TrapFrame
->Dr6
& 0xf) == 0 && KdbBreakPointToReenable
)
1536 /* FIXME: Make sure that the breakpoint was really hit (check bp->Address vs. tf->Eip) */
1537 BreakPoint
= KdbBreakPointToReenable
;
1538 KdbBreakPointToReenable
= NULL
;
1539 ASSERT(BreakPoint
->Type
== KdbBreakPointSoftware
||
1540 BreakPoint
->Type
== KdbBreakPointTemporary
);
1543 * Reenable the breakpoint we disabled to execute the breakpointed
1546 if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess
, BreakPoint
->Address
, 0xCC,
1547 &BreakPoint
->Data
.SavedInstruction
)))
1549 KdbpPrint("Warning: Couldn't reenable breakpoint %d\n",
1550 BreakPoint
- KdbBreakPoints
);
1553 /* Unset TF if we are no longer single stepping. */
1554 if (KdbNumSingleSteps
== 0)
1555 Context
->EFlags
&= ~EFLAGS_TF
;
1557 if (!KdbpEvenThoughWeHaveABreakPointToReenableWeAlsoHaveARealSingleStep
)
1559 goto continue_execution
; /* return */
1563 /* Quoth the raven, 'Nevermore!' */
1564 KdbpEvenThoughWeHaveABreakPointToReenableWeAlsoHaveARealSingleStep
= FALSE
;
1566 /* Check if we expect a single step */
1567 if ((TrapFrame
->Dr6
& 0xf) == 0 && KdbNumSingleSteps
> 0)
1569 /*ASSERT((Context->Eflags & EFLAGS_TF) != 0);*/
1570 if (--KdbNumSingleSteps
> 0)
1572 if ((KdbSingleStepOver
&& KdbpStepOverInstruction(TrapFrame
->Eip
)) ||
1573 (!KdbSingleStepOver
&& KdbpStepIntoInstruction(TrapFrame
->Eip
)))
1575 Context
->EFlags
&= ~EFLAGS_TF
;
1579 Context
->EFlags
|= EFLAGS_TF
;
1582 goto continue_execution
; /* return */
1586 Context
->EFlags
&= ~EFLAGS_TF
;
1587 KdbEnteredOnSingleStep
= TRUE
;
1592 if (!EnterConditionMet
)
1594 return kdHandleException
;
1597 KdbpPrint("\nEntered debugger on unexpected debug trap!\n");
1600 else if (ExceptionCode
== STATUS_BREAKPOINT
)
1602 if (KdbInitFileBuffer
)
1604 KdbpCliInterpretInitFile();
1605 EnterConditionMet
= FALSE
;
1607 if (!EnterConditionMet
)
1609 return kdHandleException
;
1612 KdbpPrint("\nEntered debugger on embedded INT3 at 0x%04x:0x%08x.\n",
1613 TrapFrame
->SegCs
& 0xffff, TrapFrame
->Eip
- 1);
1617 const CHAR
*ExceptionString
= (ExpNr
< RTL_NUMBER_OF(ExceptionNrToString
)) ?
1618 (ExceptionNrToString
[ExpNr
]) :
1619 ("Unknown/User defined exception");
1621 if (!EnterConditionMet
)
1623 return ContinueType
;
1626 KdbpPrint("\nEntered debugger on %s-chance exception (Exception Code: 0x%x) (%s)\n",
1627 FirstChance
? "first" : "last", ExceptionCode
, ExceptionString
);
1629 if (ExceptionCode
== STATUS_ACCESS_VIOLATION
&&
1630 ExceptionRecord
&& ExceptionRecord
->NumberParameters
!= 0)
1632 /* FIXME: Add noexec memory stuff */
1636 TrapCr2
= __readcr2();
1638 Err
= TrapFrame
->ErrCode
;
1639 KdbpPrint("Memory at 0x%p could not be %s: ", TrapCr2
, (Err
& (1 << 1)) ? "written" : "read");
1641 if ((Err
& (1 << 0)) == 0)
1643 KdbpPrint("Page not present.\n");
1647 if ((Err
& (1 << 3)) != 0)
1648 KdbpPrint("Reserved bits in page directory set.\n");
1650 KdbpPrint("Page protection violation.\n");
1655 /* Once we enter the debugger we do not expect any more single steps to happen */
1656 KdbNumSingleSteps
= 0;
1658 /* Update the current process pointer */
1659 KdbCurrentProcess
= KdbOriginalProcess
= PsGetCurrentProcess();
1660 KdbCurrentThread
= KdbOriginalThread
= PsGetCurrentThread();
1661 KdbCurrentTrapFrame
= &KdbTrapFrame
;
1663 /* Setup the KDB trap frame */
1664 KdbpTrapFrameToKdbTrapFrame(Context
, InitialTrapFrame
, &KdbTrapFrame
);
1666 /* Enter critical section */
1667 OldEflags
= __readeflags();
1670 /* HACK: Save the current IRQL and pretend we are at passive level,
1671 * although interrupts are off. Needed because KDBG calls pageable code. */
1672 OldIrql
= KeGetCurrentIrql();
1673 KeLowerIrql(PASSIVE_LEVEL
);
1675 /* Exception inside the debugger? Game over. */
1676 if (InterlockedIncrement(&KdbEntryCount
) > 1)
1678 __writeeflags(OldEflags
);
1679 return kdHandleException
;
1682 /* Call the main loop. */
1683 KdbpInternalEnter();
1685 /* Check if we should single step */
1686 if (KdbNumSingleSteps
> 0)
1688 /* Variable explains itself! */
1689 KdbpEvenThoughWeHaveABreakPointToReenableWeAlsoHaveARealSingleStep
= TRUE
;
1691 if ((KdbSingleStepOver
&& KdbpStepOverInstruction(KdbCurrentTrapFrame
->Tf
.Eip
)) ||
1692 (!KdbSingleStepOver
&& KdbpStepIntoInstruction(KdbCurrentTrapFrame
->Tf
.Eip
)))
1694 ASSERT((KdbCurrentTrapFrame
->Tf
.EFlags
& EFLAGS_TF
) == 0);
1695 /*KdbCurrentTrapFrame->Tf.EFlags &= ~EFLAGS_TF;*/
1699 Context
->EFlags
|= EFLAGS_TF
;
1703 /* We can't update the current thread's trapframe 'cause it might not have one */
1705 /* Detach from attached process */
1706 if (KdbCurrentProcess
!= KdbOriginalProcess
)
1708 KeUnstackDetachProcess(&KdbApcState
);
1711 /* Update the exception Context/TrapFrame */
1712 KdbpKdbTrapFrameToTrapFrame(&KdbTrapFrame
, Context
, InitialTrapFrame
);
1714 /* Decrement the entry count */
1715 InterlockedDecrement(&KdbEntryCount
);
1717 /* HACK: Raise back to old IRQL */
1718 KeRaiseIrql(OldIrql
, &OldIrql
);
1720 /* Leave critical section */
1721 __writeeflags(OldEflags
);
1723 /* Check if user requested a bugcheck */
1724 if (KdbpBugCheckRequested
)
1726 /* Clear the flag and bugcheck the system */
1727 KdbpBugCheckRequested
= FALSE
;
1728 KeBugCheck(MANUALLY_INITIATED_CRASH
);
1732 /* Clear debug status */
1733 if (ExceptionCode
== STATUS_BREAKPOINT
) /* FIXME: Why clear DR6 on INT3? */
1735 /* Set the RF flag so we don't trigger the same breakpoint again. */
1738 TrapFrame
->EFlags
|= EFLAGS_RF
;
1741 /* Clear dr6 status flags. */
1742 TrapFrame
->Dr6
&= ~0x0000e00f;
1744 if (!(KdbEnteredOnSingleStep
&& KdbSingleStepOver
))
1746 /* Skip the current instruction */
1751 return ContinueType
;
1757 KdbpGetCommandLineSettings(
1760 #define CONST_STR_LEN(x) (sizeof(x)/sizeof(x[0]) - 1)
1762 while (p1
&& (p1
= strchr(p1
, ' ')))
1764 /* Skip other spaces */
1765 while (*p1
== ' ') ++p1
;
1767 if (!_strnicmp(p1
, "KDSERIAL", CONST_STR_LEN("KDSERIAL")))
1769 p1
+= CONST_STR_LEN("KDSERIAL");
1770 KdbDebugState
|= KD_DEBUG_KDSERIAL
;
1771 KdpDebugMode
.Serial
= TRUE
;
1773 else if (!_strnicmp(p1
, "KDNOECHO", CONST_STR_LEN("KDNOECHO")))
1775 p1
+= CONST_STR_LEN("KDNOECHO");
1776 KdbDebugState
|= KD_DEBUG_KDNOECHO
;
1778 else if (!_strnicmp(p1
, "FIRSTCHANCE", CONST_STR_LEN("FIRSTCHANCE")))
1780 p1
+= CONST_STR_LEN("FIRSTCHANCE");
1781 KdbpSetEnterCondition(-1, TRUE
, KdbEnterAlways
);
1792 BOOLEAN Result
= TRUE
;
1800 Result
= KdpSafeReadMemory((ULONG_PTR
)Src
, Bytes
, Dest
);
1805 ULONG_PTR Start
, End
, Write
;
1807 for (Start
= (ULONG_PTR
)Src
,
1808 End
= Start
+ Bytes
,
1809 Write
= (ULONG_PTR
)Dest
;
1810 Result
&& (Start
< End
);
1812 if (!KdpSafeReadMemory(Start
, 1, (PVOID
)Write
))
1819 return Result
? STATUS_SUCCESS
: STATUS_ACCESS_VIOLATION
;
1823 KdbpSafeWriteMemory(
1828 BOOLEAN Result
= TRUE
;
1829 ULONG_PTR Start
, End
, Write
;
1831 for (Start
= (ULONG_PTR
)Src
,
1832 End
= Start
+ Bytes
,
1833 Write
= (ULONG_PTR
)Dest
;
1834 Result
&& (Start
< End
);
1836 if (!KdpSafeWriteMemory(Write
, 1, *((PCHAR
)Start
)))
1839 return Result
? STATUS_SUCCESS
: STATUS_ACCESS_VIOLATION
;