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 LONG KdbLastBreakPointNr
= -1; /* Index of the breakpoint which cause KDB to be entered */
42 ULONG KdbNumSingleSteps
= 0; /* How many single steps to do */
43 BOOLEAN KdbSingleStepOver
= FALSE
; /* Whether to step over calls/reps. */
44 ULONG KdbDebugState
= 0; /* KDBG Settings (NOECHO, KDSERIAL) */
45 static BOOLEAN KdbEnteredOnSingleStep
= FALSE
; /* Set to true when KDB was entered because of single step */
46 PEPROCESS KdbCurrentProcess
= NULL
; /* The current process context in which KDB runs */
47 PEPROCESS KdbOriginalProcess
= NULL
; /* The process in whichs context KDB was intered */
48 PETHREAD KdbCurrentThread
= NULL
; /* The current thread context in which KDB runs */
49 PETHREAD KdbOriginalThread
= NULL
; /* The thread in whichs context KDB was entered */
50 PKDB_KTRAP_FRAME KdbCurrentTrapFrame
= NULL
; /* Pointer to the current trapframe */
51 static KDB_KTRAP_FRAME KdbTrapFrame
= { { 0 } }; /* The trapframe which was passed to KdbEnterDebuggerException */
52 static KDB_KTRAP_FRAME KdbThreadTrapFrame
= { { 0 } }; /* The trapframe of the current thread (KdbCurrentThread) */
53 static KAPC_STATE KdbApcState
;
54 extern BOOLEAN KdbpBugCheckRequested
;
56 /* Array of conditions when to enter KDB */
57 static KDB_ENTER_CONDITION KdbEnterConditions
[][2] =
59 /* First chance Last chance */
60 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 0: Zero divide */
61 { KdbEnterFromKmode
, KdbDoNotEnter
}, /* 1: Debug trap */
62 { KdbDoNotEnter
, KdbEnterAlways
}, /* 2: NMI */
63 { KdbEnterFromKmode
, KdbDoNotEnter
}, /* 3: INT3 */
64 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 4: Overflow */
65 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 5: BOUND range exceeded */
66 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 6: Invalid opcode */
67 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 7: No math coprocessor fault */
68 { KdbEnterAlways
, KdbEnterAlways
}, /* 8: Double Fault */
69 { KdbEnterAlways
, KdbEnterAlways
}, /* 9: Unknown(9) */
70 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 10: Invalid TSS */
71 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 11: Segment Not Present */
72 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 12: Stack fault */
73 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 13: General protection fault */
74 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 14: Page fault */
75 { KdbEnterAlways
, KdbEnterAlways
}, /* 15: Reserved (15) */
76 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 16: FPU fault */
77 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 17: Alignment Check */
78 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 18: Machine Check */
79 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* 19: SIMD fault */
80 { KdbEnterAlways
, KdbEnterAlways
}, /* 20: Assertion failure */
81 { KdbDoNotEnter
, KdbEnterFromKmode
} /* Last entry: used for unknown exceptions */
84 /* Exception descriptions */
85 static const CHAR
*ExceptionNrToString
[] =
92 "BOUND range exceeded",
94 "No Math Coprocessor",
98 "Segment Not Present",
99 "Stack Segment Fault",
100 "General Protection",
113 IN PKTRAP_FRAME TrapFrame
);
118 IN PKTRAP_FRAME TrapFrame
);
123 IN PKTRAP_FRAME TrapFrame
,
129 IN PKTRAP_FRAME TrapFrame
,
132 /* FUNCTIONS *****************************************************************/
135 KdbpTrapFrameToKdbTrapFrame(
136 PKTRAP_FRAME TrapFrame
,
137 PKDB_KTRAP_FRAME KdbTrapFrame
)
139 ULONG TrapCr0
, TrapCr2
, TrapCr3
, TrapCr4
;
141 /* Copy the TrapFrame only up to Eflags and zero the rest*/
142 RtlCopyMemory(&KdbTrapFrame
->Tf
, TrapFrame
, FIELD_OFFSET(KTRAP_FRAME
, HardwareEsp
));
143 RtlZeroMemory((PVOID
)((ULONG_PTR
)&KdbTrapFrame
->Tf
+ FIELD_OFFSET(KTRAP_FRAME
, HardwareEsp
)),
144 sizeof(KTRAP_FRAME
) - FIELD_OFFSET(KTRAP_FRAME
, HardwareEsp
));
148 "movl %%cr0, %0" "\n\t"
149 "movl %%cr2, %1" "\n\t"
150 "movl %%cr3, %2" "\n\t"
151 "movl %%cr4, %3" "\n\t"
152 : "=r"(TrapCr0
), "=r"(TrapCr2
),
153 "=r"(TrapCr3
), "=r"(TrapCr4
));
165 /* FIXME: What's the problem with cr4? */
171 KdbTrapFrame
->Cr0
= TrapCr0
;
172 KdbTrapFrame
->Cr2
= TrapCr2
;
173 KdbTrapFrame
->Cr3
= TrapCr3
;
174 KdbTrapFrame
->Cr4
= TrapCr4
;
176 KdbTrapFrame
->Tf
.HardwareEsp
= KiEspFromTrapFrame(TrapFrame
);
177 KdbTrapFrame
->Tf
.HardwareSegSs
= (USHORT
)(KiSsFromTrapFrame(TrapFrame
) & 0xFFFF);
180 /* FIXME: copy v86 registers if TrapFrame is a V86 trapframe */
184 KdbpKdbTrapFrameToTrapFrame(
185 PKDB_KTRAP_FRAME KdbTrapFrame
,
186 PKTRAP_FRAME TrapFrame
)
188 /* Copy the TrapFrame only up to Eflags and zero the rest*/
189 RtlCopyMemory(TrapFrame
, &KdbTrapFrame
->Tf
, FIELD_OFFSET(KTRAP_FRAME
, HardwareEsp
));
191 /* FIXME: write cr0, cr2, cr3 and cr4 (not needed atm) */
193 KiSsToTrapFrame(TrapFrame
, KdbTrapFrame
->Tf
.HardwareSegSs
);
194 KiEspToTrapFrame(TrapFrame
, KdbTrapFrame
->Tf
.HardwareEsp
);
196 /* FIXME: copy v86 registers if TrapFrame is a V86 trapframe */
200 KdbpKdbTrapFrameFromKernelStack(
202 PKDB_KTRAP_FRAME KdbTrapFrame
)
206 RtlZeroMemory(KdbTrapFrame
, sizeof(KDB_KTRAP_FRAME
));
207 StackPtr
= (ULONG_PTR
*) KernelStack
;
209 KdbTrapFrame
->Tf
.Ebp
= StackPtr
[3];
210 KdbTrapFrame
->Tf
.Edi
= StackPtr
[4];
211 KdbTrapFrame
->Tf
.Esi
= StackPtr
[5];
212 KdbTrapFrame
->Tf
.Ebx
= StackPtr
[6];
213 KdbTrapFrame
->Tf
.Eip
= StackPtr
[7];
214 KdbTrapFrame
->Tf
.HardwareEsp
= (ULONG
) (StackPtr
+ 8);
215 KdbTrapFrame
->Tf
.HardwareSegSs
= KGDT_R0_DATA
;
216 KdbTrapFrame
->Tf
.SegCs
= KGDT_R0_CODE
;
217 KdbTrapFrame
->Tf
.SegDs
= KGDT_R0_DATA
;
218 KdbTrapFrame
->Tf
.SegEs
= KGDT_R0_DATA
;
219 KdbTrapFrame
->Tf
.SegGs
= KGDT_R0_DATA
;
222 /* FIXME: what about the other registers??? */
225 /*!\brief Overwrites the instruction at \a Address with \a NewInst and stores
226 * the old instruction in *OldInst.
228 * \param Process Process in which's context to overwrite the instruction.
229 * \param Address Address at which to overwrite the instruction.
230 * \param NewInst New instruction (written to \a Address)
231 * \param OldInst Old instruction (read from \a Address)
236 KdbpOverwriteInstruction(
237 IN PEPROCESS Process
,
238 IN ULONG_PTR Address
,
240 OUT PUCHAR OldInst OPTIONAL
)
244 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
247 /* Get the protection for the address. */
248 Protect
= MmGetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
));
250 /* Return if that page isn't present. */
251 if (Protect
& PAGE_NOACCESS
)
253 return STATUS_MEMORY_NOT_ALLOCATED
;
256 /* Attach to the process */
257 if (CurrentProcess
!= Process
)
259 KeStackAttachProcess(&Process
->Pcb
, &ApcState
);
262 /* Make the page writeable if it is read only. */
263 if (Protect
& (PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
))
265 MmSetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
),
266 (Protect
& ~(PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
)) | PAGE_READWRITE
);
269 /* Copy the old instruction back to the caller. */
272 Status
= KdbpSafeReadMemory(OldInst
, (PUCHAR
)Address
, 1);
273 if (!NT_SUCCESS(Status
))
275 if (Protect
& (PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
))
277 MmSetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
), Protect
);
280 /* Detach from process */
281 if (CurrentProcess
!= Process
)
290 /* Copy the new instruction in its place. */
291 Status
= KdbpSafeWriteMemory((PUCHAR
)Address
, &NewInst
, 1);
293 /* Restore the page protection. */
294 if (Protect
& (PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
))
296 MmSetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
), Protect
);
299 /* Detach from process */
300 if (CurrentProcess
!= Process
)
302 KeUnstackDetachProcess(&ApcState
);
308 /*!\brief Checks whether the given instruction can be single stepped or has to be
309 * stepped over using a temporary breakpoint.
311 * \retval TRUE Instruction is a call.
312 * \retval FALSE Instruction is not a call.
315 KdbpShouldStepOverInstruction(
321 if (!NT_SUCCESS(KdbpSafeReadMemory(Mem
, (PVOID
)Eip
, sizeof (Mem
))))
323 KdbpPrint("Couldn't access memory at 0x%p\n", Eip
);
327 /* Check if the current instruction is a call. */
328 while ((i
< sizeof (Mem
)) && (Mem
[i
] == 0x66 || Mem
[i
] == 0x67))
331 if (i
== sizeof (Mem
))
334 if (Mem
[i
] == 0xE8 || Mem
[i
] == 0x9A || Mem
[i
] == 0xF2 || Mem
[i
] == 0xF3 ||
335 (((i
+ 1) < sizeof (Mem
)) && Mem
[i
] == 0xFF && (Mem
[i
+1] & 0x38) == 0x10))
343 /*!\brief Steps over an instruction
345 * If the given instruction should be stepped over, this function inserts a
346 * temporary breakpoint after the instruction and returns TRUE, otherwise it
349 * \retval TRUE Temporary breakpoint set after instruction.
350 * \retval FALSE No breakpoint was set.
353 KdbpStepOverInstruction(
358 if (!KdbpShouldStepOverInstruction(Eip
))
361 InstLen
= KdbpGetInstLength(Eip
);
365 if (!NT_SUCCESS(KdbpInsertBreakPoint(Eip
+ InstLen
, KdbBreakPointTemporary
, 0, 0, NULL
, FALSE
, NULL
)))
371 /*!\brief Steps into an instruction (interrupts)
373 * If the given instruction should be stepped into, this function inserts a
374 * temporary breakpoint at the target instruction and returns TRUE, otherwise it
377 * \retval TRUE Temporary breakpoint set at target instruction.
378 * \retval FALSE No breakpoint was set.
381 KdbpStepIntoInstruction(
384 KDESCRIPTOR Idtr
= {0};
391 if (!NT_SUCCESS(KdbpSafeReadMemory(Mem
, (PVOID
)Eip
, sizeof (Mem
))))
393 /*KdbpPrint("Couldn't access memory at 0x%p\n", Eip);*/
397 /* Check for INT instruction */
398 /* FIXME: Check for iret */
401 else if (Mem
[0] == 0xcd)
403 else if (Mem
[0] == 0xce && KdbCurrentTrapFrame
->Tf
.EFlags
& (1<<11)) /* 1 << 11 is the overflow flag */
408 if (IntVect
< 32) /* We should be informed about interrupts < 32 by the kernel, no need to breakpoint them */
413 /* Read the interrupt descriptor table register */
415 if (IntVect
>= (Idtr
.Limit
+ 1) / 8)
417 /*KdbpPrint("IDT does not contain interrupt vector %d\n.", IntVect);*/
421 /* Get the interrupt descriptor */
422 if (!NT_SUCCESS(KdbpSafeReadMemory(IntDesc
, (PVOID
)(ULONG_PTR
)(Idtr
.Base
+ (IntVect
* 8)), sizeof (IntDesc
))))
424 /*KdbpPrint("Couldn't access memory at 0x%p\n", (ULONG_PTR)Idtr.Base + (IntVect * 8));*/
428 /* Check descriptor and get target eip (16 bit interrupt/trap gates not supported) */
429 if ((IntDesc
[1] & (1 << 15)) == 0) /* not present */
433 if ((IntDesc
[1] & 0x1f00) == 0x0500) /* Task gate */
435 /* FIXME: Task gates not supported */
438 else if (((IntDesc
[1] & 0x1fe0) == 0x0e00) || /* 32 bit Interrupt gate */
439 ((IntDesc
[1] & 0x1fe0) == 0x0f00)) /* 32 bit Trap gate */
441 /* FIXME: Should the segment selector of the interrupt gate be checked? */
442 TargetEip
= (IntDesc
[1] & 0xffff0000) | (IntDesc
[0] & 0x0000ffff);
449 /* Insert breakpoint */
450 if (!NT_SUCCESS(KdbpInsertBreakPoint(TargetEip
, KdbBreakPointTemporary
, 0, 0, NULL
, FALSE
, NULL
)))
456 /*!\brief Gets the number of the next breakpoint >= Start.
458 * \param Start Breakpoint number to start searching at. -1 if no more breakpoints are found.
460 * \returns Breakpoint number (-1 if no more breakpoints are found)
463 KdbpGetNextBreakPointNr(
464 IN ULONG Start OPTIONAL
)
466 for (; Start
< RTL_NUMBER_OF(KdbBreakPoints
); Start
++)
468 if (KdbBreakPoints
[Start
].Type
!= KdbBreakPointNone
)
475 /*!\brief Returns information of the specified breakpoint.
477 * \param BreakPointNr Number of the breakpoint to return information of.
478 * \param Address Receives the address of the breakpoint.
479 * \param Type Receives the type of the breakpoint (hardware or software)
480 * \param Size Size - for memory breakpoints.
481 * \param AccessType Access type - for hardware breakpoints.
482 * \param DebugReg Debug register - for enabled hardware breakpoints.
483 * \param Enabled Whether the breakpoint is enabled or not.
484 * \param Process The owning process of the breakpoint.
485 * \param ConditionExpression The expression which was given as condition for the bp.
487 * \returns NULL on failure, pointer to a KDB_BREAKPOINT struct on success.
490 KdbpGetBreakPointInfo(
491 IN ULONG BreakPointNr
,
492 OUT ULONG_PTR
*Address OPTIONAL
,
493 OUT KDB_BREAKPOINT_TYPE
*Type OPTIONAL
,
494 OUT UCHAR
*Size OPTIONAL
,
495 OUT KDB_ACCESS_TYPE
*AccessType OPTIONAL
,
496 OUT UCHAR
*DebugReg OPTIONAL
,
497 OUT BOOLEAN
*Enabled OPTIONAL
,
498 OUT BOOLEAN
*Global OPTIONAL
,
499 OUT PEPROCESS
*Process OPTIONAL
,
500 OUT PCHAR
*ConditionExpression OPTIONAL
)
504 if (BreakPointNr
>= RTL_NUMBER_OF(KdbBreakPoints
) ||
505 KdbBreakPoints
[BreakPointNr
].Type
== KdbBreakPointNone
)
510 bp
= KdbBreakPoints
+ BreakPointNr
;
512 *Address
= bp
->Address
;
517 if (bp
->Type
== KdbBreakPointHardware
)
520 *Size
= bp
->Data
.Hw
.Size
;
523 *AccessType
= bp
->Data
.Hw
.AccessType
;
525 if (DebugReg
&& bp
->Enabled
)
526 *DebugReg
= bp
->Data
.Hw
.DebugReg
;
530 *Enabled
= bp
->Enabled
;
533 *Global
= bp
->Global
;
536 *Process
= bp
->Process
;
538 if (ConditionExpression
)
539 *ConditionExpression
= bp
->ConditionExpression
;
544 /*!\brief Inserts a breakpoint into the breakpoint array.
546 * The \a Process of the breakpoint is set to \a KdbCurrentProcess
548 * \param Address Address at which to set the breakpoint.
549 * \param Type Type of breakpoint (hardware or software)
550 * \param Size Size of breakpoint (for hardware/memory breakpoints)
551 * \param AccessType Access type (for hardware breakpoins)
552 * \param ConditionExpression Expression which must evaluate to true for conditional breakpoints.
553 * \param Global Wether the breakpoint is global or local to a process.
554 * \param BreakPointNumber Receives the breakpoint number on success
559 KdbpInsertBreakPoint(
560 IN ULONG_PTR Address
,
561 IN KDB_BREAKPOINT_TYPE Type
,
562 IN UCHAR Size OPTIONAL
,
563 IN KDB_ACCESS_TYPE AccessType OPTIONAL
,
564 IN PCHAR ConditionExpression OPTIONAL
,
566 OUT PLONG BreakPointNr OPTIONAL
)
570 PCHAR ConditionExpressionDup
;
574 ASSERT(Type
!= KdbBreakPointNone
);
576 if (Type
== KdbBreakPointHardware
)
578 if ((Address
% Size
) != 0)
580 KdbpPrint("Address (0x%p) must be aligned to a multiple of the size (%d)\n", Address
, Size
);
581 return STATUS_UNSUCCESSFUL
;
584 if (AccessType
== KdbAccessExec
&& Size
!= 1)
586 KdbpPrint("Size must be 1 for execution breakpoints.\n");
587 return STATUS_UNSUCCESSFUL
;
591 if (KdbBreakPointCount
== KDB_MAXIMUM_BREAKPOINT_COUNT
)
593 return STATUS_UNSUCCESSFUL
;
596 /* Parse conditon expression string and duplicate it */
597 if (ConditionExpression
)
599 Condition
= KdbpRpnParseExpression(ConditionExpression
, &ErrOffset
, ErrMsg
);
603 KdbpPrint("Couldn't parse expression: %s at character %d\n", ErrMsg
, ErrOffset
);
605 KdbpPrint("Couldn't parse expression: %s", ErrMsg
);
607 return STATUS_UNSUCCESSFUL
;
610 i
= strlen(ConditionExpression
) + 1;
611 ConditionExpressionDup
= ExAllocatePoolWithTag(NonPagedPool
, i
, TAG_KDBG
);
612 RtlCopyMemory(ConditionExpressionDup
, ConditionExpression
, i
);
617 ConditionExpressionDup
= NULL
;
620 /* Find unused breakpoint */
621 if (Type
== KdbBreakPointTemporary
)
623 for (i
= RTL_NUMBER_OF(KdbBreakPoints
) - 1; i
>= 0; i
--)
625 if (KdbBreakPoints
[i
].Type
== KdbBreakPointNone
)
631 for (i
= 0; i
< (LONG
)RTL_NUMBER_OF(KdbBreakPoints
); i
++)
633 if (KdbBreakPoints
[i
].Type
== KdbBreakPointNone
)
638 ASSERT(i
< (LONG
)RTL_NUMBER_OF(KdbBreakPoints
));
640 /* Set the breakpoint */
641 ASSERT(KdbCurrentProcess
);
642 KdbBreakPoints
[i
].Type
= Type
;
643 KdbBreakPoints
[i
].Address
= Address
;
644 KdbBreakPoints
[i
].Enabled
= FALSE
;
645 KdbBreakPoints
[i
].Global
= Global
;
646 KdbBreakPoints
[i
].Process
= KdbCurrentProcess
;
647 KdbBreakPoints
[i
].ConditionExpression
= ConditionExpressionDup
;
648 KdbBreakPoints
[i
].Condition
= Condition
;
650 if (Type
== KdbBreakPointHardware
)
652 KdbBreakPoints
[i
].Data
.Hw
.Size
= Size
;
653 KdbBreakPoints
[i
].Data
.Hw
.AccessType
= AccessType
;
656 KdbBreakPointCount
++;
658 if (Type
!= KdbBreakPointTemporary
)
659 KdbpPrint("Breakpoint %d inserted.\n", i
);
661 /* Try to enable the breakpoint */
662 KdbpEnableBreakPoint(i
, NULL
);
664 /* Return the breakpoint number */
668 return STATUS_SUCCESS
;
671 /*!\brief Deletes a breakpoint
673 * \param BreakPointNr Number of the breakpoint to delete. Can be -1
674 * \param BreakPoint Breakpoint to delete. Can be NULL.
676 * \retval TRUE Success.
677 * \retval FALSE Failure (invalid breakpoint number)
680 KdbpDeleteBreakPoint(
681 IN LONG BreakPointNr OPTIONAL
,
682 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL
)
684 if (BreakPointNr
< 0)
687 BreakPointNr
= BreakPoint
- KdbBreakPoints
;
690 if (BreakPointNr
< 0 || BreakPointNr
>= KDB_MAXIMUM_BREAKPOINT_COUNT
)
692 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
698 BreakPoint
= KdbBreakPoints
+ BreakPointNr
;
701 if (BreakPoint
->Type
== KdbBreakPointNone
)
703 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
707 if (BreakPoint
->Enabled
&& !KdbpDisableBreakPoint(-1, BreakPoint
))
710 if (BreakPoint
->Type
!= KdbBreakPointTemporary
)
711 KdbpPrint("Breakpoint %d deleted.\n", BreakPointNr
);
713 BreakPoint
->Type
= KdbBreakPointNone
;
714 KdbBreakPointCount
--;
719 /*!\brief Checks if the breakpoint was set by the debugger
721 * Tries to find a breakpoint in the breakpoint array which caused
722 * the debug exception to happen.
724 * \param ExpNr Exception Number (1 or 3)
725 * \param TrapFrame Exception trapframe
727 * \returns Breakpoint number, -1 on error.
730 KdbpIsBreakPointOurs(
731 IN NTSTATUS ExceptionCode
,
732 IN PKTRAP_FRAME TrapFrame
)
735 ASSERT(ExceptionCode
== STATUS_SINGLE_STEP
|| ExceptionCode
== STATUS_BREAKPOINT
);
737 if (ExceptionCode
== STATUS_BREAKPOINT
) /* Software interrupt */
739 ULONG_PTR BpEip
= (ULONG_PTR
)TrapFrame
->Eip
- 1; /* Get EIP of INT3 instruction */
740 for (i
= 0; i
< KdbSwBreakPointCount
; i
++)
742 ASSERT((KdbSwBreakPoints
[i
]->Type
== KdbBreakPointSoftware
||
743 KdbSwBreakPoints
[i
]->Type
== KdbBreakPointTemporary
));
744 ASSERT(KdbSwBreakPoints
[i
]->Enabled
);
746 if (KdbSwBreakPoints
[i
]->Address
== BpEip
)
748 return KdbSwBreakPoints
[i
] - KdbBreakPoints
;
752 else if (ExceptionCode
== STATUS_SINGLE_STEP
) /* Hardware interrupt */
756 for (i
= 0; i
< KdbHwBreakPointCount
; i
++)
758 ASSERT(KdbHwBreakPoints
[i
]->Type
== KdbBreakPointHardware
&&
759 KdbHwBreakPoints
[i
]->Enabled
);
760 DebugReg
= KdbHwBreakPoints
[i
]->Data
.Hw
.DebugReg
;
762 if ((TrapFrame
->Dr6
& (1 << DebugReg
)) != 0)
764 return KdbHwBreakPoints
[i
] - KdbBreakPoints
;
772 /*!\brief Enables a breakpoint.
774 * \param BreakPointNr Number of the breakpoint to enable Can be -1.
775 * \param BreakPoint Breakpoint to enable. Can be NULL.
777 * \retval TRUE Success.
778 * \retval FALSE Failure.
780 * \sa KdbpDisableBreakPoint
783 KdbpEnableBreakPoint(
784 IN LONG BreakPointNr OPTIONAL
,
785 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL
)
791 if (BreakPointNr
< 0)
794 BreakPointNr
= BreakPoint
- KdbBreakPoints
;
797 if (BreakPointNr
< 0 || BreakPointNr
>= KDB_MAXIMUM_BREAKPOINT_COUNT
)
799 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
805 BreakPoint
= KdbBreakPoints
+ BreakPointNr
;
808 if (BreakPoint
->Type
== KdbBreakPointNone
)
810 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
814 if (BreakPoint
->Enabled
)
816 KdbpPrint("Breakpoint %d is already enabled.\n", BreakPointNr
);
820 if (BreakPoint
->Type
== KdbBreakPointSoftware
||
821 BreakPoint
->Type
== KdbBreakPointTemporary
)
823 if (KdbSwBreakPointCount
>= KDB_MAXIMUM_SW_BREAKPOINT_COUNT
)
825 KdbpPrint("Maximum number of SW breakpoints (%d) used. "
826 "Disable another breakpoint in order to enable this one.\n",
827 KDB_MAXIMUM_SW_BREAKPOINT_COUNT
);
831 Status
= KdbpOverwriteInstruction(BreakPoint
->Process
, BreakPoint
->Address
,
832 0xCC, &BreakPoint
->Data
.SavedInstruction
);
833 if (!NT_SUCCESS(Status
))
835 KdbpPrint("Couldn't access memory at 0x%p\n", BreakPoint
->Address
);
839 KdbSwBreakPoints
[KdbSwBreakPointCount
++] = BreakPoint
;
843 if (BreakPoint
->Data
.Hw
.AccessType
== KdbAccessExec
)
844 ASSERT(BreakPoint
->Data
.Hw
.Size
== 1);
846 ASSERT((BreakPoint
->Address
% BreakPoint
->Data
.Hw
.Size
) == 0);
848 if (KdbHwBreakPointCount
>= KDB_MAXIMUM_HW_BREAKPOINT_COUNT
)
850 KdbpPrint("Maximum number of HW breakpoints (%d) already used. "
851 "Disable another breakpoint in order to enable this one.\n",
852 KDB_MAXIMUM_HW_BREAKPOINT_COUNT
);
857 /* Find unused hw breakpoint */
858 ASSERT(KDB_MAXIMUM_HW_BREAKPOINT_COUNT
== 4);
859 for (i
= 0; i
< KDB_MAXIMUM_HW_BREAKPOINT_COUNT
; i
++)
861 if ((KdbTrapFrame
.Tf
.Dr7
& (0x3 << (i
* 2))) == 0)
865 ASSERT(i
< KDB_MAXIMUM_HW_BREAKPOINT_COUNT
);
867 /* Set the breakpoint address. */
871 KdbTrapFrame
.Tf
.Dr0
= BreakPoint
->Address
;
874 KdbTrapFrame
.Tf
.Dr1
= BreakPoint
->Address
;
877 KdbTrapFrame
.Tf
.Dr2
= BreakPoint
->Address
;
880 KdbTrapFrame
.Tf
.Dr3
= BreakPoint
->Address
;
884 /* Enable the global breakpoint */
885 KdbTrapFrame
.Tf
.Dr7
|= (0x2 << (i
* 2));
887 /* Enable the exact match bits. */
888 KdbTrapFrame
.Tf
.Dr7
|= 0x00000300;
890 /* Clear existing state. */
891 KdbTrapFrame
.Tf
.Dr7
&= ~(0xF << (16 + (i
* 4)));
893 /* Set the breakpoint type. */
894 switch (BreakPoint
->Data
.Hw
.AccessType
)
903 case KdbAccessReadWrite
:
912 KdbTrapFrame
.Tf
.Dr7
|= (ul
<< (16 + (i
* 4)));
914 /* Set the breakpoint length. */
915 KdbTrapFrame
.Tf
.Dr7
|= ((BreakPoint
->Data
.Hw
.Size
- 1) << (18 + (i
* 4)));
917 /* Update KdbCurrentTrapFrame - values are taken from there by the CLI */
918 if (&KdbTrapFrame
!= KdbCurrentTrapFrame
)
920 KdbCurrentTrapFrame
->Tf
.Dr0
= KdbTrapFrame
.Tf
.Dr0
;
921 KdbCurrentTrapFrame
->Tf
.Dr1
= KdbTrapFrame
.Tf
.Dr1
;
922 KdbCurrentTrapFrame
->Tf
.Dr2
= KdbTrapFrame
.Tf
.Dr2
;
923 KdbCurrentTrapFrame
->Tf
.Dr3
= KdbTrapFrame
.Tf
.Dr3
;
924 KdbCurrentTrapFrame
->Tf
.Dr6
= KdbTrapFrame
.Tf
.Dr6
;
925 KdbCurrentTrapFrame
->Tf
.Dr7
= KdbTrapFrame
.Tf
.Dr7
;
928 BreakPoint
->Data
.Hw
.DebugReg
= i
;
929 KdbHwBreakPoints
[KdbHwBreakPointCount
++] = BreakPoint
;
932 BreakPoint
->Enabled
= TRUE
;
933 if (BreakPoint
->Type
!= KdbBreakPointTemporary
)
934 KdbpPrint("Breakpoint %d enabled.\n", BreakPointNr
);
939 /*!\brief Disables a breakpoint.
941 * \param BreakPointNr Number of the breakpoint to disable. Can be -1
942 * \param BreakPoint Breakpoint to disable. Can be NULL.
944 * \retval TRUE Success.
945 * \retval FALSE Failure.
947 * \sa KdbpEnableBreakPoint
950 KdbpDisableBreakPoint(
951 IN LONG BreakPointNr OPTIONAL
,
952 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL
)
957 if (BreakPointNr
< 0)
960 BreakPointNr
= BreakPoint
- KdbBreakPoints
;
963 if (BreakPointNr
< 0 || BreakPointNr
>= KDB_MAXIMUM_BREAKPOINT_COUNT
)
965 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
971 BreakPoint
= KdbBreakPoints
+ BreakPointNr
;
974 if (BreakPoint
->Type
== KdbBreakPointNone
)
976 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
980 if (BreakPoint
->Enabled
== FALSE
)
982 KdbpPrint("Breakpoint %d is not enabled.\n", BreakPointNr
);
986 if (BreakPoint
->Type
== KdbBreakPointSoftware
||
987 BreakPoint
->Type
== KdbBreakPointTemporary
)
989 ASSERT(KdbSwBreakPointCount
> 0);
990 Status
= KdbpOverwriteInstruction(BreakPoint
->Process
, BreakPoint
->Address
,
991 BreakPoint
->Data
.SavedInstruction
, NULL
);
993 if (!NT_SUCCESS(Status
))
995 KdbpPrint("Couldn't restore original instruction.\n");
999 for (i
= 0; i
< KdbSwBreakPointCount
; i
++)
1001 if (KdbSwBreakPoints
[i
] == BreakPoint
)
1003 KdbSwBreakPoints
[i
] = KdbSwBreakPoints
[--KdbSwBreakPointCount
];
1004 i
= -1; /* if the last breakpoint is disabled dont break with i >= KdbSwBreakPointCount */
1009 if (i
!= MAXULONG
) /* not found */
1014 ASSERT(BreakPoint
->Type
== KdbBreakPointHardware
);
1016 /* Clear the breakpoint. */
1017 KdbTrapFrame
.Tf
.Dr7
&= ~(0x3 << (BreakPoint
->Data
.Hw
.DebugReg
* 2));
1018 if ((KdbTrapFrame
.Tf
.Dr7
& 0xFF) == 0)
1020 /* If no breakpoints are enabled then clear the exact match flags. */
1021 KdbTrapFrame
.Tf
.Dr7
&= 0xFFFFFCFF;
1024 for (i
= 0; i
< KdbHwBreakPointCount
; i
++)
1026 if (KdbHwBreakPoints
[i
] == BreakPoint
)
1028 KdbHwBreakPoints
[i
] = KdbHwBreakPoints
[--KdbHwBreakPointCount
];
1029 i
= -1; /* if the last breakpoint is disabled dont break with i >= KdbHwBreakPointCount */
1034 if (i
!= MAXULONG
) /* not found */
1038 BreakPoint
->Enabled
= FALSE
;
1039 if (BreakPoint
->Type
!= KdbBreakPointTemporary
)
1040 KdbpPrint("Breakpoint %d disabled.\n", BreakPointNr
);
1045 /*!\brief Gets the first or last chance enter-condition for exception nr. \a ExceptionNr
1047 * \param ExceptionNr Number of the exception to get condition of.
1048 * \param FirstChance Whether to get first or last chance condition.
1049 * \param Condition Receives the condition setting.
1051 * \retval TRUE Success.
1052 * \retval FALSE Failure (invalid exception nr)
1055 KdbpGetEnterCondition(
1056 IN LONG ExceptionNr
,
1057 IN BOOLEAN FirstChance
,
1058 OUT KDB_ENTER_CONDITION
*Condition
)
1060 if (ExceptionNr
>= (LONG
)RTL_NUMBER_OF(KdbEnterConditions
))
1063 *Condition
= KdbEnterConditions
[ExceptionNr
][FirstChance
? 0 : 1];
1067 /*!\brief Sets the first or last chance enter-condition for exception nr. \a ExceptionNr
1069 * \param ExceptionNr Number of the exception to set condition of (-1 for all)
1070 * \param FirstChance Whether to set first or last chance condition.
1071 * \param Condition The new condition setting.
1073 * \retval TRUE Success.
1074 * \retval FALSE Failure (invalid exception nr)
1077 KdbpSetEnterCondition(
1078 IN LONG ExceptionNr
,
1079 IN BOOLEAN FirstChance
,
1080 IN KDB_ENTER_CONDITION Condition
)
1082 if (ExceptionNr
< 0)
1084 for (ExceptionNr
= 0; ExceptionNr
< (LONG
)RTL_NUMBER_OF(KdbEnterConditions
); ExceptionNr
++)
1086 if (ExceptionNr
== 1 || ExceptionNr
== 8 ||
1087 ExceptionNr
== 9 || ExceptionNr
== 15) /* Reserved exceptions */
1092 KdbEnterConditions
[ExceptionNr
][FirstChance
? 0 : 1] = Condition
;
1097 if (ExceptionNr
>= (LONG
)RTL_NUMBER_OF(KdbEnterConditions
) ||
1098 ExceptionNr
== 1 || ExceptionNr
== 8 || /* Do not allow changing of the debug */
1099 ExceptionNr
== 9 || ExceptionNr
== 15) /* trap or reserved exceptions */
1104 KdbEnterConditions
[ExceptionNr
][FirstChance
? 0 : 1] = Condition
;
1110 /*!\brief Switches to another thread context
1112 * \param ThreadId Id of the thread to switch to.
1114 * \retval TRUE Success.
1115 * \retval FALSE Failure (i.e. invalid thread id)
1121 PETHREAD Thread
= NULL
;
1124 /* Get a pointer to the thread */
1125 if (!NT_SUCCESS(PsLookupThreadByThreadId(ThreadId
, &Thread
)))
1127 KdbpPrint("Invalid thread id: 0x%08x\n", (ULONG_PTR
)ThreadId
);
1130 Process
= Thread
->ThreadsProcess
;
1132 if (KeIsExecutingDpc() && Process
!= KdbCurrentProcess
)
1134 KdbpPrint("Cannot attach to thread within another process while executing a DPC.\n");
1135 ObDereferenceObject(Thread
);
1139 /* Save the current thread's context (if we previously attached to a thread) */
1140 if (KdbCurrentThread
!= KdbOriginalThread
)
1142 ASSERT(KdbCurrentTrapFrame
== &KdbThreadTrapFrame
);
1143 /* Actually, we can't save the context, there's no guarantee that there was a trap frame */
1147 ASSERT(KdbCurrentTrapFrame
== &KdbTrapFrame
);
1150 /* Switch to the thread's context */
1151 if (Thread
!= KdbOriginalThread
)
1153 /* The thread we're attaching to isn't the thread on which we entered
1154 * kdb and so the thread we're attaching to is not running. There
1155 * is no guarantee that it actually has a trap frame. So we have to
1156 * peek directly at the registers which were saved on the stack when the
1157 * thread was preempted in the scheduler */
1158 KdbpKdbTrapFrameFromKernelStack(Thread
->Tcb
.KernelStack
,
1159 &KdbThreadTrapFrame
);
1160 KdbCurrentTrapFrame
= &KdbThreadTrapFrame
;
1162 else /* Switching back to original thread */
1164 KdbCurrentTrapFrame
= &KdbTrapFrame
;
1166 KdbCurrentThread
= Thread
;
1168 /* Attach to the thread's process */
1169 ASSERT(KdbCurrentProcess
== PsGetCurrentProcess());
1170 if (KdbCurrentProcess
!= Process
)
1172 if (KdbCurrentProcess
!= KdbOriginalProcess
) /* detach from previously attached process */
1174 KeUnstackDetachProcess(&KdbApcState
);
1177 if (KdbOriginalProcess
!= Process
)
1179 KeStackAttachProcess(&Process
->Pcb
, &KdbApcState
);
1182 KdbCurrentProcess
= Process
;
1185 ObDereferenceObject(Thread
);
1189 /*!\brief Switches to another process/thread context
1191 * This function switches to the first thread in the specified process.
1193 * \param ProcessId Id of the process to switch to.
1195 * \retval TRUE Success.
1196 * \retval FALSE Failure (i.e. invalid process id)
1199 KdbpAttachToProcess(
1202 PEPROCESS Process
= NULL
;
1206 /* Get a pointer to the process */
1207 if (!NT_SUCCESS(PsLookupProcessByProcessId(ProcessId
, &Process
)))
1209 KdbpPrint("Invalid process id: 0x%08x\n", (ULONG_PTR
)ProcessId
);
1213 Entry
= Process
->ThreadListHead
.Flink
;
1214 ObDereferenceObject(Process
);
1215 if (Entry
== &KdbCurrentProcess
->ThreadListHead
)
1217 KdbpPrint("No threads in process 0x%p, cannot attach to process!\n", ProcessId
);
1221 Thread
= CONTAINING_RECORD(Entry
, ETHREAD
, ThreadListEntry
);
1223 return KdbpAttachToThread(Thread
->Cid
.UniqueThread
);
1226 /*!\brief Calls the main loop ...
1229 KdbpCallMainLoop(VOID
)
1231 KdbpCliMainLoop(KdbEnteredOnSingleStep
);
1234 /*!\brief Internal function to enter KDB.
1236 * Disables interrupts, releases display ownership, ...
1242 PVOID SavedInitialStack
, SavedStackBase
, SavedKernelStack
;
1243 ULONG SavedStackLimit
;
1247 if (KdpDebugMode
.Screen
&&
1248 InbvIsBootDriverInstalled() &&
1249 !InbvCheckDisplayOwnership())
1251 /* Acquire ownership and reset the display */
1252 InbvAcquireDisplayOwnership();
1255 /* Display debugger prompt */
1256 InbvSolidColorFill(0, 0, 639, 479, 0);
1257 InbvSetTextColor(15);
1258 InbvInstallDisplayStringFilter(NULL
);
1259 InbvEnableDisplayString(TRUE
);
1260 InbvSetScrollRegion(0, 0, 639, 479);
1263 /* Call the interface's main loop on a different stack */
1264 Thread
= PsGetCurrentThread();
1265 SavedInitialStack
= Thread
->Tcb
.InitialStack
;
1266 SavedStackBase
= Thread
->Tcb
.StackBase
;
1267 SavedStackLimit
= Thread
->Tcb
.StackLimit
;
1268 SavedKernelStack
= Thread
->Tcb
.KernelStack
;
1269 Thread
->Tcb
.InitialStack
= Thread
->Tcb
.StackBase
= (char*)KdbStack
+ KDB_STACK_SIZE
;
1270 Thread
->Tcb
.StackLimit
= (ULONG_PTR
)KdbStack
;
1271 Thread
->Tcb
.KernelStack
= (char*)KdbStack
+ KDB_STACK_SIZE
;
1273 /*KdbpPrint("Switching to KDB stack 0x%08x-0x%08x (Current Stack is 0x%08x)\n", Thread->Tcb.StackLimit, Thread->Tcb.StackBase, Esp);*/
1275 KdbpStackSwitchAndCall(KdbStack
+ KDB_STACK_SIZE
- sizeof(ULONG
), KdbpCallMainLoop
);
1277 Thread
->Tcb
.InitialStack
= SavedInitialStack
;
1278 Thread
->Tcb
.StackBase
= SavedStackBase
;
1279 Thread
->Tcb
.StackLimit
= SavedStackLimit
;
1280 Thread
->Tcb
.KernelStack
= SavedKernelStack
;
1285 KdbpGetExceptionNumberFromStatus(
1286 IN NTSTATUS ExceptionCode
)
1290 switch (ExceptionCode
)
1292 case STATUS_INTEGER_DIVIDE_BY_ZERO
:
1295 case STATUS_SINGLE_STEP
:
1298 case STATUS_BREAKPOINT
:
1301 case STATUS_INTEGER_OVERFLOW
:
1304 case STATUS_ARRAY_BOUNDS_EXCEEDED
:
1307 case STATUS_ILLEGAL_INSTRUCTION
:
1310 case STATUS_FLOAT_INVALID_OPERATION
:
1313 case STATUS_STACK_OVERFLOW
:
1316 case STATUS_ACCESS_VIOLATION
:
1319 case STATUS_DATATYPE_MISALIGNMENT
:
1322 case STATUS_FLOAT_MULTIPLE_TRAPS
:
1325 case STATUS_ASSERTION_FAILURE
:
1330 Ret
= RTL_NUMBER_OF(KdbEnterConditions
) - 1;
1337 /*!\brief KDB Exception filter
1339 * Called by the exception dispatcher.
1341 * \param ExceptionRecord Unused.
1342 * \param PreviousMode UserMode if the exception was raised from umode, otherwise KernelMode.
1343 * \param Context Context, IN/OUT parameter.
1344 * \param TrapFrame Exception TrapFrame.
1345 * \param FirstChance TRUE when called before exception frames were serached,
1346 * FALSE for the second call.
1348 * \returns KD_CONTINUE_TYPE
1351 KdbEnterDebuggerException(
1352 IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL
,
1353 IN KPROCESSOR_MODE PreviousMode
,
1354 IN PCONTEXT Context
,
1355 IN OUT PKTRAP_FRAME TrapFrame
,
1356 IN BOOLEAN FirstChance
)
1358 KDB_ENTER_CONDITION EnterCondition
;
1359 KD_CONTINUE_TYPE ContinueType
= kdHandleException
;
1360 PKDB_BREAKPOINT BreakPoint
;
1363 BOOLEAN Resume
= FALSE
;
1364 BOOLEAN EnterConditionMet
= TRUE
;
1367 NTSTATUS ExceptionCode
;
1369 ExceptionCode
= (ExceptionRecord
? ExceptionRecord
->ExceptionCode
: STATUS_BREAKPOINT
);
1371 KdbCurrentProcess
= PsGetCurrentProcess();
1373 /* Set continue type to kdContinue for single steps and breakpoints */
1374 if (ExceptionCode
== STATUS_SINGLE_STEP
|| ExceptionCode
== STATUS_BREAKPOINT
)
1375 ContinueType
= kdContinue
;
1377 /* Check if we should handle the exception. */
1378 /* FIXME - won't get all exceptions here :( */
1379 ExpNr
= KdbpGetExceptionNumberFromStatus(ExceptionCode
);
1380 EnterCondition
= KdbEnterConditions
[ExpNr
][FirstChance
? 0 : 1];
1381 if (EnterCondition
== KdbDoNotEnter
||
1382 (EnterCondition
== KdbEnterFromUmode
&& PreviousMode
== KernelMode
) ||
1383 (EnterCondition
== KdbEnterFromKmode
&& PreviousMode
!= KernelMode
))
1385 EnterConditionMet
= FALSE
;
1388 /* If we stopped on one of our breakpoints then let the user know. */
1389 KdbLastBreakPointNr
= -1;
1390 KdbEnteredOnSingleStep
= FALSE
;
1392 if (FirstChance
&& (ExceptionCode
== STATUS_SINGLE_STEP
|| ExceptionCode
== STATUS_BREAKPOINT
) &&
1393 (KdbLastBreakPointNr
= KdbpIsBreakPointOurs(ExceptionCode
, TrapFrame
)) >= 0)
1395 BreakPoint
= KdbBreakPoints
+ KdbLastBreakPointNr
;
1397 if (ExceptionCode
== STATUS_BREAKPOINT
)
1399 /* ... and restore the original instruction. */
1400 if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess
, BreakPoint
->Address
,
1401 BreakPoint
->Data
.SavedInstruction
, NULL
)))
1403 KdbpPrint("Couldn't restore original instruction after INT3! Cannot continue execution.\n");
1404 KeBugCheck(0); // FIXME: Proper bugcode!
1408 if ((BreakPoint
->Type
== KdbBreakPointHardware
) &&
1409 (BreakPoint
->Data
.Hw
.AccessType
== KdbAccessExec
))
1411 Resume
= TRUE
; /* Set the resume flag when continuing execution */
1415 * When a temporary breakpoint is hit we have to make sure that we are
1416 * in the same context in which it was set, otherwise it could happen
1417 * that another process/thread hits it before and it gets deleted.
1419 else if (BreakPoint
->Type
== KdbBreakPointTemporary
&&
1420 BreakPoint
->Process
== KdbCurrentProcess
)
1422 ASSERT((TrapFrame
->EFlags
& EFLAGS_TF
) == 0);
1424 /* Delete the temporary breakpoint which was used to step over or into the instruction. */
1425 KdbpDeleteBreakPoint(-1, BreakPoint
);
1429 if (--KdbNumSingleSteps
> 0)
1431 if ((KdbSingleStepOver
&& !KdbpStepOverInstruction(TrapFrame
->Eip
)) ||
1432 (!KdbSingleStepOver
&& !KdbpStepIntoInstruction(TrapFrame
->Eip
)))
1434 Context
->EFlags
|= EFLAGS_TF
;
1437 goto continue_execution
; /* return */
1440 KdbEnteredOnSingleStep
= TRUE
;
1444 * If we hit a breakpoint set by the debugger we set the single step flag,
1445 * ignore the next single step and reenable the breakpoint.
1447 else if (BreakPoint
->Type
== KdbBreakPointSoftware
||
1448 BreakPoint
->Type
== KdbBreakPointTemporary
)
1450 ASSERT(ExceptionCode
== STATUS_BREAKPOINT
);
1451 Context
->EFlags
|= EFLAGS_TF
;
1452 KdbBreakPointToReenable
= BreakPoint
;
1455 /* Make sure that the breakpoint should be triggered in this context */
1456 if (!BreakPoint
->Global
&& BreakPoint
->Process
!= KdbCurrentProcess
)
1458 goto continue_execution
; /* return */
1461 /* Check if the condition for the breakpoint is met. */
1462 if (BreakPoint
->Condition
)
1464 /* Setup the KDB trap frame */
1465 KdbpTrapFrameToKdbTrapFrame(TrapFrame
, &KdbTrapFrame
);
1468 if (!KdbpRpnEvaluateParsedExpression(BreakPoint
->Condition
, &KdbTrapFrame
, &ull
, NULL
, NULL
))
1470 /* FIXME: Print warning? */
1472 else if (ull
== 0) /* condition is not met */
1474 goto continue_execution
; /* return */
1478 if (BreakPoint
->Type
== KdbBreakPointSoftware
)
1480 KdbpPrint("\nEntered debugger on breakpoint #%d: EXEC 0x%04x:0x%08x\n",
1481 KdbLastBreakPointNr
, TrapFrame
->SegCs
& 0xffff, TrapFrame
->Eip
);
1483 else if (BreakPoint
->Type
== KdbBreakPointHardware
)
1485 KdbpPrint("\nEntered debugger on breakpoint #%d: %s 0x%08x\n",
1486 KdbLastBreakPointNr
,
1487 (BreakPoint
->Data
.Hw
.AccessType
== KdbAccessRead
) ? "READ" :
1488 ((BreakPoint
->Data
.Hw
.AccessType
== KdbAccessWrite
) ? "WRITE" :
1489 ((BreakPoint
->Data
.Hw
.AccessType
== KdbAccessReadWrite
) ? "RDWR" : "EXEC")),
1490 BreakPoint
->Address
);
1493 else if (ExceptionCode
== STATUS_SINGLE_STEP
)
1495 /* Silently ignore a debugger initiated single step. */
1496 if ((TrapFrame
->Dr6
& 0xf) == 0 && KdbBreakPointToReenable
)
1498 /* FIXME: Make sure that the breakpoint was really hit (check bp->Address vs. tf->Eip) */
1499 BreakPoint
= KdbBreakPointToReenable
;
1500 KdbBreakPointToReenable
= NULL
;
1501 ASSERT(BreakPoint
->Type
== KdbBreakPointSoftware
||
1502 BreakPoint
->Type
== KdbBreakPointTemporary
);
1505 * Reenable the breakpoint we disabled to execute the breakpointed
1508 if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess
, BreakPoint
->Address
, 0xCC,
1509 &BreakPoint
->Data
.SavedInstruction
)))
1511 KdbpPrint("Warning: Couldn't reenable breakpoint %d\n",
1512 BreakPoint
- KdbBreakPoints
);
1515 /* Unset TF if we are no longer single stepping. */
1516 if (KdbNumSingleSteps
== 0)
1517 Context
->EFlags
&= ~EFLAGS_TF
;
1519 goto continue_execution
; /* return */
1522 /* Check if we expect a single step */
1523 if ((TrapFrame
->Dr6
& 0xf) == 0 && KdbNumSingleSteps
> 0)
1525 /*ASSERT((Context->Eflags & EFLAGS_TF) != 0);*/
1526 if (--KdbNumSingleSteps
> 0)
1528 if ((KdbSingleStepOver
&& KdbpStepOverInstruction(TrapFrame
->Eip
)) ||
1529 (!KdbSingleStepOver
&& KdbpStepIntoInstruction(TrapFrame
->Eip
)))
1531 Context
->EFlags
&= ~EFLAGS_TF
;
1535 Context
->EFlags
|= EFLAGS_TF
;
1538 goto continue_execution
; /* return */
1542 Context
->EFlags
&= ~EFLAGS_TF
;
1543 KdbEnteredOnSingleStep
= TRUE
;
1548 if (!EnterConditionMet
)
1550 return kdHandleException
;
1553 KdbpPrint("\nEntered debugger on unexpected debug trap!\n");
1556 else if (ExceptionCode
== STATUS_BREAKPOINT
)
1558 if (KdbInitFileBuffer
)
1560 KdbpCliInterpretInitFile();
1561 EnterConditionMet
= FALSE
;
1563 if (!EnterConditionMet
)
1565 return kdHandleException
;
1568 KdbpPrint("\nEntered debugger on embedded INT3 at 0x%04x:0x%08x.\n",
1569 TrapFrame
->SegCs
& 0xffff, TrapFrame
->Eip
- 1);
1573 const CHAR
*ExceptionString
= (ExpNr
< RTL_NUMBER_OF(ExceptionNrToString
)) ?
1574 (ExceptionNrToString
[ExpNr
]) :
1575 ("Unknown/User defined exception");
1577 if (!EnterConditionMet
)
1579 return ContinueType
;
1582 KdbpPrint("\nEntered debugger on %s-chance exception (Exception Code: 0x%x) (%s)\n",
1583 FirstChance
? "first" : "last", ExceptionCode
, ExceptionString
);
1585 if (ExceptionCode
== STATUS_ACCESS_VIOLATION
&&
1586 ExceptionRecord
&& ExceptionRecord
->NumberParameters
!= 0)
1588 /* FIXME: Add noexec memory stuff */
1592 TrapCr2
= __readcr2();
1594 Err
= TrapFrame
->ErrCode
;
1595 KdbpPrint("Memory at 0x%p could not be %s: ", TrapCr2
, (Err
& (1 << 1)) ? "written" : "read");
1597 if ((Err
& (1 << 0)) == 0)
1599 KdbpPrint("Page not present.\n");
1603 if ((Err
& (1 << 3)) != 0)
1604 KdbpPrint("Reserved bits in page directory set.\n");
1606 KdbpPrint("Page protection violation.\n");
1611 /* Once we enter the debugger we do not expect any more single steps to happen */
1612 KdbNumSingleSteps
= 0;
1614 /* Update the current process pointer */
1615 KdbCurrentProcess
= KdbOriginalProcess
= PsGetCurrentProcess();
1616 KdbCurrentThread
= KdbOriginalThread
= PsGetCurrentThread();
1617 KdbCurrentTrapFrame
= &KdbTrapFrame
;
1619 /* Setup the KDB trap frame */
1620 KdbpTrapFrameToKdbTrapFrame(TrapFrame
, &KdbTrapFrame
);
1622 /* Enter critical section */
1623 OldEflags
= __readeflags();
1626 /* HACK: Save the current IRQL and pretend we are at passive level,
1627 * although interrupts are off. Needed because KDBG calls pageable code. */
1628 OldIrql
= KeGetCurrentIrql();
1629 KeLowerIrql(PASSIVE_LEVEL
);
1631 /* Exception inside the debugger? Game over. */
1632 if (InterlockedIncrement(&KdbEntryCount
) > 1)
1634 __writeeflags(OldEflags
);
1635 return kdHandleException
;
1638 /* Call the main loop. */
1639 KdbpInternalEnter();
1641 /* Check if we should single step */
1642 if (KdbNumSingleSteps
> 0)
1644 if ((KdbSingleStepOver
&& KdbpStepOverInstruction(KdbCurrentTrapFrame
->Tf
.Eip
)) ||
1645 (!KdbSingleStepOver
&& KdbpStepIntoInstruction(KdbCurrentTrapFrame
->Tf
.Eip
)))
1647 ASSERT((KdbCurrentTrapFrame
->Tf
.EFlags
& EFLAGS_TF
) == 0);
1648 /*KdbCurrentTrapFrame->Tf.EFlags &= ~EFLAGS_TF;*/
1652 Context
->EFlags
|= EFLAGS_TF
;
1656 /* We can't update the current thread's trapframe 'cause it might not have one */
1658 /* Detach from attached process */
1659 if (KdbCurrentProcess
!= KdbOriginalProcess
)
1661 KeUnstackDetachProcess(&KdbApcState
);
1664 /* Update the exception TrapFrame */
1665 KdbpKdbTrapFrameToTrapFrame(&KdbTrapFrame
, TrapFrame
);
1667 /* Decrement the entry count */
1668 InterlockedDecrement(&KdbEntryCount
);
1670 /* HACK: Raise back to old IRQL */
1671 KeRaiseIrql(OldIrql
, &OldIrql
);
1673 /* Leave critical section */
1674 __writeeflags(OldEflags
);
1676 /* Check if user requested a bugcheck */
1677 if (KdbpBugCheckRequested
)
1679 /* Clear the flag and bugcheck the system */
1680 KdbpBugCheckRequested
= FALSE
;
1681 KeBugCheck(MANUALLY_INITIATED_CRASH
);
1685 /* Clear debug status */
1686 if (ExceptionCode
== STATUS_BREAKPOINT
) /* FIXME: Why clear DR6 on INT3? */
1688 /* Set the RF flag so we don't trigger the same breakpoint again. */
1691 TrapFrame
->EFlags
|= EFLAGS_RF
;
1694 /* Clear dr6 status flags. */
1695 TrapFrame
->Dr6
&= ~0x0000e00f;
1697 if (!(KdbEnteredOnSingleStep
&& KdbSingleStepOver
))
1699 /* Skip the current instruction */
1704 return ContinueType
;
1710 KdbpGetCommandLineSettings(
1713 #define CONST_STR_LEN(x) (sizeof(x)/sizeof(x[0]) - 1)
1715 while (p1
&& (p1
= strchr(p1
, ' ')))
1717 /* Skip other spaces */
1718 while (*p1
== ' ') ++p1
;
1720 if (!_strnicmp(p1
, "KDSERIAL", CONST_STR_LEN("KDSERIAL")))
1722 p1
+= CONST_STR_LEN("KDSERIAL");
1723 KdbDebugState
|= KD_DEBUG_KDSERIAL
;
1724 KdpDebugMode
.Serial
= TRUE
;
1726 else if (!_strnicmp(p1
, "KDNOECHO", CONST_STR_LEN("KDNOECHO")))
1728 p1
+= CONST_STR_LEN("KDNOECHO");
1729 KdbDebugState
|= KD_DEBUG_KDNOECHO
;
1731 else if (!_strnicmp(p1
, "FIRSTCHANCE", CONST_STR_LEN("FIRSTCHANCE")))
1733 p1
+= CONST_STR_LEN("FIRSTCHANCE");
1734 KdbpSetEnterCondition(-1, TRUE
, KdbEnterAlways
);
1745 BOOLEAN Result
= TRUE
;
1753 Result
= KdpSafeReadMemory((ULONG_PTR
)Src
, Bytes
, Dest
);
1758 ULONG_PTR Start
, End
, Write
;
1760 for (Start
= (ULONG_PTR
)Src
,
1761 End
= Start
+ Bytes
,
1762 Write
= (ULONG_PTR
)Dest
;
1763 Result
&& (Start
< End
);
1765 if (!KdpSafeReadMemory(Start
, 1, (PVOID
)Write
))
1772 return Result
? STATUS_SUCCESS
: STATUS_ACCESS_VIOLATION
;
1776 KdbpSafeWriteMemory(
1781 BOOLEAN Result
= TRUE
;
1782 ULONG_PTR Start
, End
, Write
;
1784 for (Start
= (ULONG_PTR
)Src
,
1785 End
= Start
+ Bytes
,
1786 Write
= (ULONG_PTR
)Dest
;
1787 Result
&& (Start
< End
);
1789 if (!KdpSafeWriteMemory(Write
, 1, *((PCHAR
)Start
)))
1792 return Result
? STATUS_SUCCESS
: STATUS_ACCESS_VIOLATION
;