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(
137 PKTRAP_FRAME TrapFrame
,
138 PKDB_KTRAP_FRAME KdbTrapFrame
)
140 /* Copy the TrapFrame only up to Eflags and zero the rest*/
141 RtlCopyMemory(&KdbTrapFrame
->Tf
, TrapFrame
, FIELD_OFFSET(KTRAP_FRAME
, HardwareEsp
));
142 RtlZeroMemory((PVOID
)((ULONG_PTR
)&KdbTrapFrame
->Tf
+ FIELD_OFFSET(KTRAP_FRAME
, HardwareEsp
)),
143 sizeof(KTRAP_FRAME
) - FIELD_OFFSET(KTRAP_FRAME
, HardwareEsp
));
145 KdbTrapFrame
->Cr0
= __readcr0();
146 KdbTrapFrame
->Cr2
= __readcr2();
147 KdbTrapFrame
->Cr3
= __readcr3();
148 KdbTrapFrame
->Cr4
= __readcr4();
150 KdbTrapFrame
->Tf
.HardwareEsp
= KiEspFromTrapFrame(TrapFrame
);
151 KdbTrapFrame
->Tf
.HardwareSegSs
= (USHORT
)(KiSsFromTrapFrame(TrapFrame
) & 0xFFFF);
154 /* FIXME: copy v86 registers if TrapFrame is a V86 trapframe */
158 KdbpKdbTrapFrameToTrapFrame(
159 PKDB_KTRAP_FRAME KdbTrapFrame
,
160 PKTRAP_FRAME TrapFrame
)
162 /* Copy the TrapFrame only up to Eflags and zero the rest*/
163 RtlCopyMemory(TrapFrame
, &KdbTrapFrame
->Tf
, FIELD_OFFSET(KTRAP_FRAME
, HardwareEsp
));
165 /* FIXME: write cr0, cr2, cr3 and cr4 (not needed atm) */
167 KiSsToTrapFrame(TrapFrame
, KdbTrapFrame
->Tf
.HardwareSegSs
);
168 KiEspToTrapFrame(TrapFrame
, KdbTrapFrame
->Tf
.HardwareEsp
);
170 /* FIXME: copy v86 registers if TrapFrame is a V86 trapframe */
174 KdbpKdbTrapFrameFromKernelStack(
176 PKDB_KTRAP_FRAME KdbTrapFrame
)
180 RtlZeroMemory(KdbTrapFrame
, sizeof(KDB_KTRAP_FRAME
));
181 StackPtr
= (ULONG_PTR
*) KernelStack
;
183 KdbTrapFrame
->Tf
.Ebp
= StackPtr
[3];
184 KdbTrapFrame
->Tf
.Edi
= StackPtr
[4];
185 KdbTrapFrame
->Tf
.Esi
= StackPtr
[5];
186 KdbTrapFrame
->Tf
.Ebx
= StackPtr
[6];
187 KdbTrapFrame
->Tf
.Eip
= StackPtr
[7];
188 KdbTrapFrame
->Tf
.HardwareEsp
= (ULONG
) (StackPtr
+ 8);
189 KdbTrapFrame
->Tf
.HardwareSegSs
= KGDT_R0_DATA
;
190 KdbTrapFrame
->Tf
.SegCs
= KGDT_R0_CODE
;
191 KdbTrapFrame
->Tf
.SegDs
= KGDT_R0_DATA
;
192 KdbTrapFrame
->Tf
.SegEs
= KGDT_R0_DATA
;
193 KdbTrapFrame
->Tf
.SegGs
= KGDT_R0_DATA
;
196 /* FIXME: what about the other registers??? */
199 /*!\brief Overwrites the instruction at \a Address with \a NewInst and stores
200 * the old instruction in *OldInst.
202 * \param Process Process in which's context to overwrite the instruction.
203 * \param Address Address at which to overwrite the instruction.
204 * \param NewInst New instruction (written to \a Address)
205 * \param OldInst Old instruction (read from \a Address)
210 KdbpOverwriteInstruction(
211 IN PEPROCESS Process
,
212 IN ULONG_PTR Address
,
214 OUT PUCHAR OldInst OPTIONAL
)
218 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
221 /* Get the protection for the address. */
222 Protect
= MmGetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
));
224 /* Return if that page isn't present. */
225 if (Protect
& PAGE_NOACCESS
)
227 return STATUS_MEMORY_NOT_ALLOCATED
;
230 /* Attach to the process */
231 if (CurrentProcess
!= Process
)
233 KeStackAttachProcess(&Process
->Pcb
, &ApcState
);
236 /* Make the page writeable if it is read only. */
237 if (Protect
& (PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
))
239 MmSetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
),
240 (Protect
& ~(PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
)) | PAGE_READWRITE
);
243 /* Copy the old instruction back to the caller. */
246 Status
= KdbpSafeReadMemory(OldInst
, (PUCHAR
)Address
, 1);
247 if (!NT_SUCCESS(Status
))
249 if (Protect
& (PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
))
251 MmSetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
), Protect
);
254 /* Detach from process */
255 if (CurrentProcess
!= Process
)
264 /* Copy the new instruction in its place. */
265 Status
= KdbpSafeWriteMemory((PUCHAR
)Address
, &NewInst
, 1);
267 /* Restore the page protection. */
268 if (Protect
& (PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
))
270 MmSetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
), Protect
);
273 /* Detach from process */
274 if (CurrentProcess
!= Process
)
276 KeUnstackDetachProcess(&ApcState
);
282 /*!\brief Checks whether the given instruction can be single stepped or has to be
283 * stepped over using a temporary breakpoint.
285 * \retval TRUE Instruction is a call.
286 * \retval FALSE Instruction is not a call.
289 KdbpShouldStepOverInstruction(
295 if (!NT_SUCCESS(KdbpSafeReadMemory(Mem
, (PVOID
)Eip
, sizeof (Mem
))))
297 KdbpPrint("Couldn't access memory at 0x%p\n", Eip
);
301 /* Check if the current instruction is a call. */
302 while ((i
< sizeof (Mem
)) && (Mem
[i
] == 0x66 || Mem
[i
] == 0x67))
305 if (i
== sizeof (Mem
))
308 if (Mem
[i
] == 0xE8 || Mem
[i
] == 0x9A || Mem
[i
] == 0xF2 || Mem
[i
] == 0xF3 ||
309 (((i
+ 1) < sizeof (Mem
)) && Mem
[i
] == 0xFF && (Mem
[i
+1] & 0x38) == 0x10))
317 /*!\brief Steps over an instruction
319 * If the given instruction should be stepped over, this function inserts a
320 * temporary breakpoint after the instruction and returns TRUE, otherwise it
323 * \retval TRUE Temporary breakpoint set after instruction.
324 * \retval FALSE No breakpoint was set.
327 KdbpStepOverInstruction(
332 if (!KdbpShouldStepOverInstruction(Eip
))
335 InstLen
= KdbpGetInstLength(Eip
);
339 if (!NT_SUCCESS(KdbpInsertBreakPoint(Eip
+ InstLen
, KdbBreakPointTemporary
, 0, 0, NULL
, FALSE
, NULL
)))
345 /*!\brief Steps into an instruction (interrupts)
347 * If the given instruction should be stepped into, this function inserts a
348 * temporary breakpoint at the target instruction and returns TRUE, otherwise it
351 * \retval TRUE Temporary breakpoint set at target instruction.
352 * \retval FALSE No breakpoint was set.
355 KdbpStepIntoInstruction(
358 KDESCRIPTOR Idtr
= {0};
365 if (!NT_SUCCESS(KdbpSafeReadMemory(Mem
, (PVOID
)Eip
, sizeof (Mem
))))
367 /*KdbpPrint("Couldn't access memory at 0x%p\n", Eip);*/
371 /* Check for INT instruction */
372 /* FIXME: Check for iret */
375 else if (Mem
[0] == 0xcd)
377 else if (Mem
[0] == 0xce && KdbCurrentTrapFrame
->Tf
.EFlags
& (1<<11)) /* 1 << 11 is the overflow flag */
382 if (IntVect
< 32) /* We should be informed about interrupts < 32 by the kernel, no need to breakpoint them */
387 /* Read the interrupt descriptor table register */
389 if (IntVect
>= (Idtr
.Limit
+ 1) / 8)
391 /*KdbpPrint("IDT does not contain interrupt vector %d\n.", IntVect);*/
395 /* Get the interrupt descriptor */
396 if (!NT_SUCCESS(KdbpSafeReadMemory(IntDesc
, (PVOID
)(ULONG_PTR
)(Idtr
.Base
+ (IntVect
* 8)), sizeof (IntDesc
))))
398 /*KdbpPrint("Couldn't access memory at 0x%p\n", (ULONG_PTR)Idtr.Base + (IntVect * 8));*/
402 /* Check descriptor and get target eip (16 bit interrupt/trap gates not supported) */
403 if ((IntDesc
[1] & (1 << 15)) == 0) /* not present */
407 if ((IntDesc
[1] & 0x1f00) == 0x0500) /* Task gate */
409 /* FIXME: Task gates not supported */
412 else if (((IntDesc
[1] & 0x1fe0) == 0x0e00) || /* 32 bit Interrupt gate */
413 ((IntDesc
[1] & 0x1fe0) == 0x0f00)) /* 32 bit Trap gate */
415 /* FIXME: Should the segment selector of the interrupt gate be checked? */
416 TargetEip
= (IntDesc
[1] & 0xffff0000) | (IntDesc
[0] & 0x0000ffff);
423 /* Insert breakpoint */
424 if (!NT_SUCCESS(KdbpInsertBreakPoint(TargetEip
, KdbBreakPointTemporary
, 0, 0, NULL
, FALSE
, NULL
)))
430 /*!\brief Gets the number of the next breakpoint >= Start.
432 * \param Start Breakpoint number to start searching at. -1 if no more breakpoints are found.
434 * \returns Breakpoint number (-1 if no more breakpoints are found)
437 KdbpGetNextBreakPointNr(
438 IN ULONG Start OPTIONAL
)
440 for (; Start
< RTL_NUMBER_OF(KdbBreakPoints
); Start
++)
442 if (KdbBreakPoints
[Start
].Type
!= KdbBreakPointNone
)
449 /*!\brief Returns information of the specified breakpoint.
451 * \param BreakPointNr Number of the breakpoint to return information of.
452 * \param Address Receives the address of the breakpoint.
453 * \param Type Receives the type of the breakpoint (hardware or software)
454 * \param Size Size - for memory breakpoints.
455 * \param AccessType Access type - for hardware breakpoints.
456 * \param DebugReg Debug register - for enabled hardware breakpoints.
457 * \param Enabled Whether the breakpoint is enabled or not.
458 * \param Process The owning process of the breakpoint.
459 * \param ConditionExpression The expression which was given as condition for the bp.
461 * \returns NULL on failure, pointer to a KDB_BREAKPOINT struct on success.
464 KdbpGetBreakPointInfo(
465 IN ULONG BreakPointNr
,
466 OUT ULONG_PTR
*Address OPTIONAL
,
467 OUT KDB_BREAKPOINT_TYPE
*Type OPTIONAL
,
468 OUT UCHAR
*Size OPTIONAL
,
469 OUT KDB_ACCESS_TYPE
*AccessType OPTIONAL
,
470 OUT UCHAR
*DebugReg OPTIONAL
,
471 OUT BOOLEAN
*Enabled OPTIONAL
,
472 OUT BOOLEAN
*Global OPTIONAL
,
473 OUT PEPROCESS
*Process OPTIONAL
,
474 OUT PCHAR
*ConditionExpression OPTIONAL
)
478 if (BreakPointNr
>= RTL_NUMBER_OF(KdbBreakPoints
) ||
479 KdbBreakPoints
[BreakPointNr
].Type
== KdbBreakPointNone
)
484 bp
= KdbBreakPoints
+ BreakPointNr
;
486 *Address
= bp
->Address
;
491 if (bp
->Type
== KdbBreakPointHardware
)
494 *Size
= bp
->Data
.Hw
.Size
;
497 *AccessType
= bp
->Data
.Hw
.AccessType
;
499 if (DebugReg
&& bp
->Enabled
)
500 *DebugReg
= bp
->Data
.Hw
.DebugReg
;
504 *Enabled
= bp
->Enabled
;
507 *Global
= bp
->Global
;
510 *Process
= bp
->Process
;
512 if (ConditionExpression
)
513 *ConditionExpression
= bp
->ConditionExpression
;
518 /*!\brief Inserts a breakpoint into the breakpoint array.
520 * The \a Process of the breakpoint is set to \a KdbCurrentProcess
522 * \param Address Address at which to set the breakpoint.
523 * \param Type Type of breakpoint (hardware or software)
524 * \param Size Size of breakpoint (for hardware/memory breakpoints)
525 * \param AccessType Access type (for hardware breakpoins)
526 * \param ConditionExpression Expression which must evaluate to true for conditional breakpoints.
527 * \param Global Wether the breakpoint is global or local to a process.
528 * \param BreakPointNumber Receives the breakpoint number on success
533 KdbpInsertBreakPoint(
534 IN ULONG_PTR Address
,
535 IN KDB_BREAKPOINT_TYPE Type
,
536 IN UCHAR Size OPTIONAL
,
537 IN KDB_ACCESS_TYPE AccessType OPTIONAL
,
538 IN PCHAR ConditionExpression OPTIONAL
,
540 OUT PLONG BreakPointNr OPTIONAL
)
544 PCHAR ConditionExpressionDup
;
548 ASSERT(Type
!= KdbBreakPointNone
);
550 if (Type
== KdbBreakPointHardware
)
552 if ((Address
% Size
) != 0)
554 KdbpPrint("Address (0x%p) must be aligned to a multiple of the size (%d)\n", Address
, Size
);
555 return STATUS_UNSUCCESSFUL
;
558 if (AccessType
== KdbAccessExec
&& Size
!= 1)
560 KdbpPrint("Size must be 1 for execution breakpoints.\n");
561 return STATUS_UNSUCCESSFUL
;
565 if (KdbBreakPointCount
== KDB_MAXIMUM_BREAKPOINT_COUNT
)
567 return STATUS_UNSUCCESSFUL
;
570 /* Parse conditon expression string and duplicate it */
571 if (ConditionExpression
)
573 Condition
= KdbpRpnParseExpression(ConditionExpression
, &ErrOffset
, ErrMsg
);
577 KdbpPrint("Couldn't parse expression: %s at character %d\n", ErrMsg
, ErrOffset
);
579 KdbpPrint("Couldn't parse expression: %s", ErrMsg
);
581 return STATUS_UNSUCCESSFUL
;
584 i
= strlen(ConditionExpression
) + 1;
585 ConditionExpressionDup
= ExAllocatePoolWithTag(NonPagedPool
, i
, TAG_KDBG
);
586 RtlCopyMemory(ConditionExpressionDup
, ConditionExpression
, i
);
591 ConditionExpressionDup
= NULL
;
594 /* Find unused breakpoint */
595 if (Type
== KdbBreakPointTemporary
)
597 for (i
= RTL_NUMBER_OF(KdbBreakPoints
) - 1; i
>= 0; i
--)
599 if (KdbBreakPoints
[i
].Type
== KdbBreakPointNone
)
605 for (i
= 0; i
< (LONG
)RTL_NUMBER_OF(KdbBreakPoints
); i
++)
607 if (KdbBreakPoints
[i
].Type
== KdbBreakPointNone
)
612 ASSERT(i
< (LONG
)RTL_NUMBER_OF(KdbBreakPoints
));
614 /* Set the breakpoint */
615 ASSERT(KdbCurrentProcess
);
616 KdbBreakPoints
[i
].Type
= Type
;
617 KdbBreakPoints
[i
].Address
= Address
;
618 KdbBreakPoints
[i
].Enabled
= FALSE
;
619 KdbBreakPoints
[i
].Global
= Global
;
620 KdbBreakPoints
[i
].Process
= KdbCurrentProcess
;
621 KdbBreakPoints
[i
].ConditionExpression
= ConditionExpressionDup
;
622 KdbBreakPoints
[i
].Condition
= Condition
;
624 if (Type
== KdbBreakPointHardware
)
626 KdbBreakPoints
[i
].Data
.Hw
.Size
= Size
;
627 KdbBreakPoints
[i
].Data
.Hw
.AccessType
= AccessType
;
630 KdbBreakPointCount
++;
632 if (Type
!= KdbBreakPointTemporary
)
633 KdbpPrint("Breakpoint %d inserted.\n", i
);
635 /* Try to enable the breakpoint */
636 KdbpEnableBreakPoint(i
, NULL
);
638 /* Return the breakpoint number */
642 return STATUS_SUCCESS
;
645 /*!\brief Deletes a breakpoint
647 * \param BreakPointNr Number of the breakpoint to delete. Can be -1
648 * \param BreakPoint Breakpoint to delete. Can be NULL.
650 * \retval TRUE Success.
651 * \retval FALSE Failure (invalid breakpoint number)
654 KdbpDeleteBreakPoint(
655 IN LONG BreakPointNr OPTIONAL
,
656 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL
)
658 if (BreakPointNr
< 0)
661 BreakPointNr
= BreakPoint
- KdbBreakPoints
;
664 if (BreakPointNr
< 0 || BreakPointNr
>= KDB_MAXIMUM_BREAKPOINT_COUNT
)
666 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
672 BreakPoint
= KdbBreakPoints
+ BreakPointNr
;
675 if (BreakPoint
->Type
== KdbBreakPointNone
)
677 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
681 if (BreakPoint
->Enabled
&& !KdbpDisableBreakPoint(-1, BreakPoint
))
684 if (BreakPoint
->Type
!= KdbBreakPointTemporary
)
685 KdbpPrint("Breakpoint %d deleted.\n", BreakPointNr
);
687 BreakPoint
->Type
= KdbBreakPointNone
;
688 KdbBreakPointCount
--;
693 /*!\brief Checks if the breakpoint was set by the debugger
695 * Tries to find a breakpoint in the breakpoint array which caused
696 * the debug exception to happen.
698 * \param ExpNr Exception Number (1 or 3)
699 * \param TrapFrame Exception trapframe
701 * \returns Breakpoint number, -1 on error.
704 KdbpIsBreakPointOurs(
705 IN NTSTATUS ExceptionCode
,
706 IN PKTRAP_FRAME TrapFrame
)
709 ASSERT(ExceptionCode
== STATUS_SINGLE_STEP
|| ExceptionCode
== STATUS_BREAKPOINT
);
711 if (ExceptionCode
== STATUS_BREAKPOINT
) /* Software interrupt */
713 ULONG_PTR BpEip
= (ULONG_PTR
)TrapFrame
->Eip
- 1; /* Get EIP of INT3 instruction */
714 for (i
= 0; i
< KdbSwBreakPointCount
; i
++)
716 ASSERT((KdbSwBreakPoints
[i
]->Type
== KdbBreakPointSoftware
||
717 KdbSwBreakPoints
[i
]->Type
== KdbBreakPointTemporary
));
718 ASSERT(KdbSwBreakPoints
[i
]->Enabled
);
720 if (KdbSwBreakPoints
[i
]->Address
== BpEip
)
722 return KdbSwBreakPoints
[i
] - KdbBreakPoints
;
726 else if (ExceptionCode
== STATUS_SINGLE_STEP
) /* Hardware interrupt */
730 for (i
= 0; i
< KdbHwBreakPointCount
; i
++)
732 ASSERT(KdbHwBreakPoints
[i
]->Type
== KdbBreakPointHardware
&&
733 KdbHwBreakPoints
[i
]->Enabled
);
734 DebugReg
= KdbHwBreakPoints
[i
]->Data
.Hw
.DebugReg
;
736 if ((TrapFrame
->Dr6
& (1 << DebugReg
)) != 0)
738 return KdbHwBreakPoints
[i
] - KdbBreakPoints
;
746 /*!\brief Enables a breakpoint.
748 * \param BreakPointNr Number of the breakpoint to enable Can be -1.
749 * \param BreakPoint Breakpoint to enable. Can be NULL.
751 * \retval TRUE Success.
752 * \retval FALSE Failure.
754 * \sa KdbpDisableBreakPoint
757 KdbpEnableBreakPoint(
758 IN LONG BreakPointNr OPTIONAL
,
759 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL
)
765 if (BreakPointNr
< 0)
768 BreakPointNr
= BreakPoint
- KdbBreakPoints
;
771 if (BreakPointNr
< 0 || BreakPointNr
>= KDB_MAXIMUM_BREAKPOINT_COUNT
)
773 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
779 BreakPoint
= KdbBreakPoints
+ BreakPointNr
;
782 if (BreakPoint
->Type
== KdbBreakPointNone
)
784 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
788 if (BreakPoint
->Enabled
)
790 KdbpPrint("Breakpoint %d is already enabled.\n", BreakPointNr
);
794 if (BreakPoint
->Type
== KdbBreakPointSoftware
||
795 BreakPoint
->Type
== KdbBreakPointTemporary
)
797 if (KdbSwBreakPointCount
>= KDB_MAXIMUM_SW_BREAKPOINT_COUNT
)
799 KdbpPrint("Maximum number of SW breakpoints (%d) used. "
800 "Disable another breakpoint in order to enable this one.\n",
801 KDB_MAXIMUM_SW_BREAKPOINT_COUNT
);
805 Status
= KdbpOverwriteInstruction(BreakPoint
->Process
, BreakPoint
->Address
,
806 0xCC, &BreakPoint
->Data
.SavedInstruction
);
807 if (!NT_SUCCESS(Status
))
809 KdbpPrint("Couldn't access memory at 0x%p\n", BreakPoint
->Address
);
813 KdbSwBreakPoints
[KdbSwBreakPointCount
++] = BreakPoint
;
817 if (BreakPoint
->Data
.Hw
.AccessType
== KdbAccessExec
)
818 ASSERT(BreakPoint
->Data
.Hw
.Size
== 1);
820 ASSERT((BreakPoint
->Address
% BreakPoint
->Data
.Hw
.Size
) == 0);
822 if (KdbHwBreakPointCount
>= KDB_MAXIMUM_HW_BREAKPOINT_COUNT
)
824 KdbpPrint("Maximum number of HW breakpoints (%d) already used. "
825 "Disable another breakpoint in order to enable this one.\n",
826 KDB_MAXIMUM_HW_BREAKPOINT_COUNT
);
831 /* Find unused hw breakpoint */
832 ASSERT(KDB_MAXIMUM_HW_BREAKPOINT_COUNT
== 4);
833 for (i
= 0; i
< KDB_MAXIMUM_HW_BREAKPOINT_COUNT
; i
++)
835 if ((KdbTrapFrame
.Tf
.Dr7
& (0x3 << (i
* 2))) == 0)
839 ASSERT(i
< KDB_MAXIMUM_HW_BREAKPOINT_COUNT
);
841 /* Set the breakpoint address. */
845 KdbTrapFrame
.Tf
.Dr0
= BreakPoint
->Address
;
848 KdbTrapFrame
.Tf
.Dr1
= BreakPoint
->Address
;
851 KdbTrapFrame
.Tf
.Dr2
= BreakPoint
->Address
;
854 KdbTrapFrame
.Tf
.Dr3
= BreakPoint
->Address
;
858 /* Enable the global breakpoint */
859 KdbTrapFrame
.Tf
.Dr7
|= (0x2 << (i
* 2));
861 /* Enable the exact match bits. */
862 KdbTrapFrame
.Tf
.Dr7
|= 0x00000300;
864 /* Clear existing state. */
865 KdbTrapFrame
.Tf
.Dr7
&= ~(0xF << (16 + (i
* 4)));
867 /* Set the breakpoint type. */
868 switch (BreakPoint
->Data
.Hw
.AccessType
)
877 case KdbAccessReadWrite
:
886 KdbTrapFrame
.Tf
.Dr7
|= (ul
<< (16 + (i
* 4)));
888 /* Set the breakpoint length. */
889 KdbTrapFrame
.Tf
.Dr7
|= ((BreakPoint
->Data
.Hw
.Size
- 1) << (18 + (i
* 4)));
891 /* Update KdbCurrentTrapFrame - values are taken from there by the CLI */
892 if (&KdbTrapFrame
!= KdbCurrentTrapFrame
)
894 KdbCurrentTrapFrame
->Tf
.Dr0
= KdbTrapFrame
.Tf
.Dr0
;
895 KdbCurrentTrapFrame
->Tf
.Dr1
= KdbTrapFrame
.Tf
.Dr1
;
896 KdbCurrentTrapFrame
->Tf
.Dr2
= KdbTrapFrame
.Tf
.Dr2
;
897 KdbCurrentTrapFrame
->Tf
.Dr3
= KdbTrapFrame
.Tf
.Dr3
;
898 KdbCurrentTrapFrame
->Tf
.Dr6
= KdbTrapFrame
.Tf
.Dr6
;
899 KdbCurrentTrapFrame
->Tf
.Dr7
= KdbTrapFrame
.Tf
.Dr7
;
902 BreakPoint
->Data
.Hw
.DebugReg
= i
;
903 KdbHwBreakPoints
[KdbHwBreakPointCount
++] = BreakPoint
;
906 BreakPoint
->Enabled
= TRUE
;
907 if (BreakPoint
->Type
!= KdbBreakPointTemporary
)
908 KdbpPrint("Breakpoint %d enabled.\n", BreakPointNr
);
913 /*!\brief Disables a breakpoint.
915 * \param BreakPointNr Number of the breakpoint to disable. Can be -1
916 * \param BreakPoint Breakpoint to disable. Can be NULL.
918 * \retval TRUE Success.
919 * \retval FALSE Failure.
921 * \sa KdbpEnableBreakPoint
924 KdbpDisableBreakPoint(
925 IN LONG BreakPointNr OPTIONAL
,
926 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL
)
931 if (BreakPointNr
< 0)
934 BreakPointNr
= BreakPoint
- KdbBreakPoints
;
937 if (BreakPointNr
< 0 || BreakPointNr
>= KDB_MAXIMUM_BREAKPOINT_COUNT
)
939 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
945 BreakPoint
= KdbBreakPoints
+ BreakPointNr
;
948 if (BreakPoint
->Type
== KdbBreakPointNone
)
950 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
954 if (BreakPoint
->Enabled
== FALSE
)
956 KdbpPrint("Breakpoint %d is not enabled.\n", BreakPointNr
);
960 if (BreakPoint
->Type
== KdbBreakPointSoftware
||
961 BreakPoint
->Type
== KdbBreakPointTemporary
)
963 ASSERT(KdbSwBreakPointCount
> 0);
964 Status
= KdbpOverwriteInstruction(BreakPoint
->Process
, BreakPoint
->Address
,
965 BreakPoint
->Data
.SavedInstruction
, NULL
);
967 if (!NT_SUCCESS(Status
))
969 KdbpPrint("Couldn't restore original instruction.\n");
973 for (i
= 0; i
< KdbSwBreakPointCount
; i
++)
975 if (KdbSwBreakPoints
[i
] == BreakPoint
)
977 KdbSwBreakPoints
[i
] = KdbSwBreakPoints
[--KdbSwBreakPointCount
];
978 i
= -1; /* if the last breakpoint is disabled dont break with i >= KdbSwBreakPointCount */
983 if (i
!= MAXULONG
) /* not found */
988 ASSERT(BreakPoint
->Type
== KdbBreakPointHardware
);
990 /* Clear the breakpoint. */
991 KdbTrapFrame
.Tf
.Dr7
&= ~(0x3 << (BreakPoint
->Data
.Hw
.DebugReg
* 2));
992 if ((KdbTrapFrame
.Tf
.Dr7
& 0xFF) == 0)
994 /* If no breakpoints are enabled then clear the exact match flags. */
995 KdbTrapFrame
.Tf
.Dr7
&= 0xFFFFFCFF;
998 for (i
= 0; i
< KdbHwBreakPointCount
; i
++)
1000 if (KdbHwBreakPoints
[i
] == BreakPoint
)
1002 KdbHwBreakPoints
[i
] = KdbHwBreakPoints
[--KdbHwBreakPointCount
];
1003 i
= -1; /* if the last breakpoint is disabled dont break with i >= KdbHwBreakPointCount */
1008 if (i
!= MAXULONG
) /* not found */
1012 BreakPoint
->Enabled
= FALSE
;
1013 if (BreakPoint
->Type
!= KdbBreakPointTemporary
)
1014 KdbpPrint("Breakpoint %d disabled.\n", BreakPointNr
);
1019 /*!\brief Gets the first or last chance enter-condition for exception nr. \a ExceptionNr
1021 * \param ExceptionNr Number of the exception to get condition of.
1022 * \param FirstChance Whether to get first or last chance condition.
1023 * \param Condition Receives the condition setting.
1025 * \retval TRUE Success.
1026 * \retval FALSE Failure (invalid exception nr)
1029 KdbpGetEnterCondition(
1030 IN LONG ExceptionNr
,
1031 IN BOOLEAN FirstChance
,
1032 OUT KDB_ENTER_CONDITION
*Condition
)
1034 if (ExceptionNr
>= (LONG
)RTL_NUMBER_OF(KdbEnterConditions
))
1037 *Condition
= KdbEnterConditions
[ExceptionNr
][FirstChance
? 0 : 1];
1041 /*!\brief Sets the first or last chance enter-condition for exception nr. \a ExceptionNr
1043 * \param ExceptionNr Number of the exception to set condition of (-1 for all)
1044 * \param FirstChance Whether to set first or last chance condition.
1045 * \param Condition The new condition setting.
1047 * \retval TRUE Success.
1048 * \retval FALSE Failure (invalid exception nr)
1051 KdbpSetEnterCondition(
1052 IN LONG ExceptionNr
,
1053 IN BOOLEAN FirstChance
,
1054 IN KDB_ENTER_CONDITION Condition
)
1056 if (ExceptionNr
< 0)
1058 for (ExceptionNr
= 0; ExceptionNr
< (LONG
)RTL_NUMBER_OF(KdbEnterConditions
); ExceptionNr
++)
1060 if (ExceptionNr
== 1 || ExceptionNr
== 8 ||
1061 ExceptionNr
== 9 || ExceptionNr
== 15) /* Reserved exceptions */
1066 KdbEnterConditions
[ExceptionNr
][FirstChance
? 0 : 1] = Condition
;
1071 if (ExceptionNr
>= (LONG
)RTL_NUMBER_OF(KdbEnterConditions
) ||
1072 ExceptionNr
== 1 || ExceptionNr
== 8 || /* Do not allow changing of the debug */
1073 ExceptionNr
== 9 || ExceptionNr
== 15) /* trap or reserved exceptions */
1078 KdbEnterConditions
[ExceptionNr
][FirstChance
? 0 : 1] = Condition
;
1084 /*!\brief Switches to another thread context
1086 * \param ThreadId Id of the thread to switch to.
1088 * \retval TRUE Success.
1089 * \retval FALSE Failure (i.e. invalid thread id)
1095 PETHREAD Thread
= NULL
;
1098 /* Get a pointer to the thread */
1099 if (!NT_SUCCESS(PsLookupThreadByThreadId(ThreadId
, &Thread
)))
1101 KdbpPrint("Invalid thread id: 0x%08x\n", (ULONG_PTR
)ThreadId
);
1104 Process
= Thread
->ThreadsProcess
;
1106 if (KeIsExecutingDpc() && Process
!= KdbCurrentProcess
)
1108 KdbpPrint("Cannot attach to thread within another process while executing a DPC.\n");
1109 ObDereferenceObject(Thread
);
1113 /* Save the current thread's context (if we previously attached to a thread) */
1114 if (KdbCurrentThread
!= KdbOriginalThread
)
1116 ASSERT(KdbCurrentTrapFrame
== &KdbThreadTrapFrame
);
1117 /* Actually, we can't save the context, there's no guarantee that there was a trap frame */
1121 ASSERT(KdbCurrentTrapFrame
== &KdbTrapFrame
);
1124 /* Switch to the thread's context */
1125 if (Thread
!= KdbOriginalThread
)
1127 /* The thread we're attaching to isn't the thread on which we entered
1128 * kdb and so the thread we're attaching to is not running. There
1129 * is no guarantee that it actually has a trap frame. So we have to
1130 * peek directly at the registers which were saved on the stack when the
1131 * thread was preempted in the scheduler */
1132 KdbpKdbTrapFrameFromKernelStack(Thread
->Tcb
.KernelStack
,
1133 &KdbThreadTrapFrame
);
1134 KdbCurrentTrapFrame
= &KdbThreadTrapFrame
;
1136 else /* Switching back to original thread */
1138 KdbCurrentTrapFrame
= &KdbTrapFrame
;
1140 KdbCurrentThread
= Thread
;
1142 /* Attach to the thread's process */
1143 ASSERT(KdbCurrentProcess
== PsGetCurrentProcess());
1144 if (KdbCurrentProcess
!= Process
)
1146 if (KdbCurrentProcess
!= KdbOriginalProcess
) /* detach from previously attached process */
1148 KeUnstackDetachProcess(&KdbApcState
);
1151 if (KdbOriginalProcess
!= Process
)
1153 KeStackAttachProcess(&Process
->Pcb
, &KdbApcState
);
1156 KdbCurrentProcess
= Process
;
1159 ObDereferenceObject(Thread
);
1163 /*!\brief Switches to another process/thread context
1165 * This function switches to the first thread in the specified process.
1167 * \param ProcessId Id of the process to switch to.
1169 * \retval TRUE Success.
1170 * \retval FALSE Failure (i.e. invalid process id)
1173 KdbpAttachToProcess(
1176 PEPROCESS Process
= NULL
;
1180 /* Get a pointer to the process */
1181 if (!NT_SUCCESS(PsLookupProcessByProcessId(ProcessId
, &Process
)))
1183 KdbpPrint("Invalid process id: 0x%08x\n", (ULONG_PTR
)ProcessId
);
1187 Entry
= Process
->ThreadListHead
.Flink
;
1188 ObDereferenceObject(Process
);
1189 if (Entry
== &KdbCurrentProcess
->ThreadListHead
)
1191 KdbpPrint("No threads in process 0x%p, cannot attach to process!\n", ProcessId
);
1195 Thread
= CONTAINING_RECORD(Entry
, ETHREAD
, ThreadListEntry
);
1197 return KdbpAttachToThread(Thread
->Cid
.UniqueThread
);
1200 /*!\brief Calls the main loop ...
1203 KdbpCallMainLoop(VOID
)
1205 KdbpCliMainLoop(KdbEnteredOnSingleStep
);
1208 /*!\brief Internal function to enter KDB.
1210 * Disables interrupts, releases display ownership, ...
1213 KdbpInternalEnter(VOID
)
1216 PVOID SavedInitialStack
, SavedStackBase
, SavedKernelStack
;
1217 ULONG SavedStackLimit
;
1221 if (KdpDebugMode
.Screen
&&
1222 InbvIsBootDriverInstalled() &&
1223 !InbvCheckDisplayOwnership())
1225 /* Acquire ownership and reset the display */
1226 InbvAcquireDisplayOwnership();
1229 /* Display debugger prompt */
1230 InbvSolidColorFill(0, 0, 639, 479, 0);
1231 InbvSetTextColor(15);
1232 InbvInstallDisplayStringFilter(NULL
);
1233 InbvEnableDisplayString(TRUE
);
1234 InbvSetScrollRegion(0, 0, 639, 479);
1237 /* Call the interface's main loop on a different stack */
1238 Thread
= PsGetCurrentThread();
1239 SavedInitialStack
= Thread
->Tcb
.InitialStack
;
1240 SavedStackBase
= Thread
->Tcb
.StackBase
;
1241 SavedStackLimit
= Thread
->Tcb
.StackLimit
;
1242 SavedKernelStack
= Thread
->Tcb
.KernelStack
;
1243 Thread
->Tcb
.InitialStack
= Thread
->Tcb
.StackBase
= (char*)KdbStack
+ KDB_STACK_SIZE
;
1244 Thread
->Tcb
.StackLimit
= (ULONG_PTR
)KdbStack
;
1245 Thread
->Tcb
.KernelStack
= (char*)KdbStack
+ KDB_STACK_SIZE
;
1247 /*KdbpPrint("Switching to KDB stack 0x%08x-0x%08x (Current Stack is 0x%08x)\n", Thread->Tcb.StackLimit, Thread->Tcb.StackBase, Esp);*/
1249 KdbpStackSwitchAndCall(KdbStack
+ KDB_STACK_SIZE
- sizeof(ULONG
), KdbpCallMainLoop
);
1251 Thread
->Tcb
.InitialStack
= SavedInitialStack
;
1252 Thread
->Tcb
.StackBase
= SavedStackBase
;
1253 Thread
->Tcb
.StackLimit
= SavedStackLimit
;
1254 Thread
->Tcb
.KernelStack
= SavedKernelStack
;
1259 KdbpGetExceptionNumberFromStatus(
1260 IN NTSTATUS ExceptionCode
)
1264 switch (ExceptionCode
)
1266 case STATUS_INTEGER_DIVIDE_BY_ZERO
:
1269 case STATUS_SINGLE_STEP
:
1272 case STATUS_BREAKPOINT
:
1275 case STATUS_INTEGER_OVERFLOW
:
1278 case STATUS_ARRAY_BOUNDS_EXCEEDED
:
1281 case STATUS_ILLEGAL_INSTRUCTION
:
1284 case STATUS_FLOAT_INVALID_OPERATION
:
1287 case STATUS_STACK_OVERFLOW
:
1290 case STATUS_ACCESS_VIOLATION
:
1293 case STATUS_DATATYPE_MISALIGNMENT
:
1296 case STATUS_FLOAT_MULTIPLE_TRAPS
:
1299 case STATUS_ASSERTION_FAILURE
:
1304 Ret
= RTL_NUMBER_OF(KdbEnterConditions
) - 1;
1311 /*!\brief KDB Exception filter
1313 * Called by the exception dispatcher.
1315 * \param ExceptionRecord Unused.
1316 * \param PreviousMode UserMode if the exception was raised from umode, otherwise KernelMode.
1317 * \param Context Context, IN/OUT parameter.
1318 * \param TrapFrame Exception TrapFrame.
1319 * \param FirstChance TRUE when called before exception frames were serached,
1320 * FALSE for the second call.
1322 * \returns KD_CONTINUE_TYPE
1325 KdbEnterDebuggerException(
1326 IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL
,
1327 IN KPROCESSOR_MODE PreviousMode
,
1328 IN PCONTEXT Context
,
1329 IN OUT PKTRAP_FRAME TrapFrame
,
1330 IN BOOLEAN FirstChance
)
1332 KDB_ENTER_CONDITION EnterCondition
;
1333 KD_CONTINUE_TYPE ContinueType
= kdHandleException
;
1334 PKDB_BREAKPOINT BreakPoint
;
1337 BOOLEAN Resume
= FALSE
;
1338 BOOLEAN EnterConditionMet
= TRUE
;
1341 NTSTATUS ExceptionCode
;
1343 ExceptionCode
= (ExceptionRecord
? ExceptionRecord
->ExceptionCode
: STATUS_BREAKPOINT
);
1345 KdbCurrentProcess
= PsGetCurrentProcess();
1347 /* Set continue type to kdContinue for single steps and breakpoints */
1348 if (ExceptionCode
== STATUS_SINGLE_STEP
||
1349 ExceptionCode
== STATUS_BREAKPOINT
||
1350 ExceptionCode
== STATUS_ASSERTION_FAILURE
)
1352 ContinueType
= kdContinue
;
1355 /* Check if we should handle the exception. */
1356 /* FIXME - won't get all exceptions here :( */
1357 ExpNr
= KdbpGetExceptionNumberFromStatus(ExceptionCode
);
1358 EnterCondition
= KdbEnterConditions
[ExpNr
][FirstChance
? 0 : 1];
1359 if (EnterCondition
== KdbDoNotEnter
||
1360 (EnterCondition
== KdbEnterFromUmode
&& PreviousMode
== KernelMode
) ||
1361 (EnterCondition
== KdbEnterFromKmode
&& PreviousMode
!= KernelMode
))
1363 EnterConditionMet
= FALSE
;
1366 /* If we stopped on one of our breakpoints then let the user know. */
1367 KdbLastBreakPointNr
= -1;
1368 KdbEnteredOnSingleStep
= FALSE
;
1370 if (FirstChance
&& (ExceptionCode
== STATUS_SINGLE_STEP
|| ExceptionCode
== STATUS_BREAKPOINT
) &&
1371 (KdbLastBreakPointNr
= KdbpIsBreakPointOurs(ExceptionCode
, TrapFrame
)) >= 0)
1373 BreakPoint
= KdbBreakPoints
+ KdbLastBreakPointNr
;
1375 if (ExceptionCode
== STATUS_BREAKPOINT
)
1377 /* ... and restore the original instruction. */
1378 if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess
, BreakPoint
->Address
,
1379 BreakPoint
->Data
.SavedInstruction
, NULL
)))
1381 KdbpPrint("Couldn't restore original instruction after INT3! Cannot continue execution.\n");
1382 KeBugCheck(0); // FIXME: Proper bugcode!
1385 /* Also since we are past the int3 now, decrement EIP in the
1386 TrapFrame. This is only needed because KDBG insists on working
1387 with the TrapFrame instead of with the Context, as it is supposed
1388 to do. The context has already EIP point to the int3, since
1389 KiDispatchException accounts for that. Whatever we do here with
1390 the TrapFrame does not matter anyway, since KiDispatchException
1391 will overwrite it with the values from the Context! */
1395 if ((BreakPoint
->Type
== KdbBreakPointHardware
) &&
1396 (BreakPoint
->Data
.Hw
.AccessType
== KdbAccessExec
))
1398 Resume
= TRUE
; /* Set the resume flag when continuing execution */
1402 * When a temporary breakpoint is hit we have to make sure that we are
1403 * in the same context in which it was set, otherwise it could happen
1404 * that another process/thread hits it before and it gets deleted.
1406 else if (BreakPoint
->Type
== KdbBreakPointTemporary
&&
1407 BreakPoint
->Process
== KdbCurrentProcess
)
1409 ASSERT((TrapFrame
->EFlags
& EFLAGS_TF
) == 0);
1411 /* Delete the temporary breakpoint which was used to step over or into the instruction. */
1412 KdbpDeleteBreakPoint(-1, BreakPoint
);
1414 if (--KdbNumSingleSteps
> 0)
1416 if ((KdbSingleStepOver
&& !KdbpStepOverInstruction(TrapFrame
->Eip
)) ||
1417 (!KdbSingleStepOver
&& !KdbpStepIntoInstruction(TrapFrame
->Eip
)))
1419 Context
->EFlags
|= EFLAGS_TF
;
1422 goto continue_execution
; /* return */
1425 KdbEnteredOnSingleStep
= TRUE
;
1429 * If we hit a breakpoint set by the debugger we set the single step flag,
1430 * ignore the next single step and reenable the breakpoint.
1432 else if (BreakPoint
->Type
== KdbBreakPointSoftware
||
1433 BreakPoint
->Type
== KdbBreakPointTemporary
)
1435 ASSERT(ExceptionCode
== STATUS_BREAKPOINT
);
1436 Context
->EFlags
|= EFLAGS_TF
;
1437 KdbBreakPointToReenable
= BreakPoint
;
1440 /* Make sure that the breakpoint should be triggered in this context */
1441 if (!BreakPoint
->Global
&& BreakPoint
->Process
!= KdbCurrentProcess
)
1443 goto continue_execution
; /* return */
1446 /* Check if the condition for the breakpoint is met. */
1447 if (BreakPoint
->Condition
)
1449 /* Setup the KDB trap frame */
1450 KdbpTrapFrameToKdbTrapFrame(TrapFrame
, &KdbTrapFrame
);
1453 if (!KdbpRpnEvaluateParsedExpression(BreakPoint
->Condition
, &KdbTrapFrame
, &ull
, NULL
, NULL
))
1455 /* FIXME: Print warning? */
1457 else if (ull
== 0) /* condition is not met */
1459 goto continue_execution
; /* return */
1463 if (BreakPoint
->Type
== KdbBreakPointSoftware
)
1465 KdbpPrint("\nEntered debugger on breakpoint #%d: EXEC 0x%04x:0x%08x\n",
1466 KdbLastBreakPointNr
, TrapFrame
->SegCs
& 0xffff, TrapFrame
->Eip
);
1468 else if (BreakPoint
->Type
== KdbBreakPointHardware
)
1470 KdbpPrint("\nEntered debugger on breakpoint #%d: %s 0x%08x\n",
1471 KdbLastBreakPointNr
,
1472 (BreakPoint
->Data
.Hw
.AccessType
== KdbAccessRead
) ? "READ" :
1473 ((BreakPoint
->Data
.Hw
.AccessType
== KdbAccessWrite
) ? "WRITE" :
1474 ((BreakPoint
->Data
.Hw
.AccessType
== KdbAccessReadWrite
) ? "RDWR" : "EXEC")),
1475 BreakPoint
->Address
);
1478 else if (ExceptionCode
== STATUS_SINGLE_STEP
)
1480 /* Silently ignore a debugger initiated single step. */
1481 if ((TrapFrame
->Dr6
& 0xf) == 0 && KdbBreakPointToReenable
)
1483 /* FIXME: Make sure that the breakpoint was really hit (check bp->Address vs. tf->Eip) */
1484 BreakPoint
= KdbBreakPointToReenable
;
1485 KdbBreakPointToReenable
= NULL
;
1486 ASSERT(BreakPoint
->Type
== KdbBreakPointSoftware
||
1487 BreakPoint
->Type
== KdbBreakPointTemporary
);
1490 * Reenable the breakpoint we disabled to execute the breakpointed
1493 if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess
, BreakPoint
->Address
, 0xCC,
1494 &BreakPoint
->Data
.SavedInstruction
)))
1496 KdbpPrint("Warning: Couldn't reenable breakpoint %d\n",
1497 BreakPoint
- KdbBreakPoints
);
1500 /* Unset TF if we are no longer single stepping. */
1501 if (KdbNumSingleSteps
== 0)
1502 Context
->EFlags
&= ~EFLAGS_TF
;
1504 if (!KdbpEvenThoughWeHaveABreakPointToReenableWeAlsoHaveARealSingleStep
)
1506 goto continue_execution
; /* return */
1510 /* Quoth the raven, 'Nevermore!' */
1511 KdbpEvenThoughWeHaveABreakPointToReenableWeAlsoHaveARealSingleStep
= FALSE
;
1513 /* Check if we expect a single step */
1514 if ((TrapFrame
->Dr6
& 0xf) == 0 && KdbNumSingleSteps
> 0)
1516 /*ASSERT((Context->Eflags & EFLAGS_TF) != 0);*/
1517 if (--KdbNumSingleSteps
> 0)
1519 if ((KdbSingleStepOver
&& KdbpStepOverInstruction(TrapFrame
->Eip
)) ||
1520 (!KdbSingleStepOver
&& KdbpStepIntoInstruction(TrapFrame
->Eip
)))
1522 Context
->EFlags
&= ~EFLAGS_TF
;
1526 Context
->EFlags
|= EFLAGS_TF
;
1529 goto continue_execution
; /* return */
1533 Context
->EFlags
&= ~EFLAGS_TF
;
1534 KdbEnteredOnSingleStep
= TRUE
;
1539 if (!EnterConditionMet
)
1541 return kdHandleException
;
1544 KdbpPrint("\nEntered debugger on unexpected debug trap!\n");
1547 else if (ExceptionCode
== STATUS_BREAKPOINT
)
1549 if (KdbInitFileBuffer
)
1551 KdbpCliInterpretInitFile();
1552 EnterConditionMet
= FALSE
;
1554 if (!EnterConditionMet
)
1556 return kdHandleException
;
1559 KdbpPrint("\nEntered debugger on embedded INT3 at 0x%04x:0x%08x.\n",
1560 TrapFrame
->SegCs
& 0xffff, TrapFrame
->Eip
- 1);
1564 const CHAR
*ExceptionString
= (ExpNr
< RTL_NUMBER_OF(ExceptionNrToString
)) ?
1565 (ExceptionNrToString
[ExpNr
]) :
1566 ("Unknown/User defined exception");
1568 if (!EnterConditionMet
)
1570 return ContinueType
;
1573 KdbpPrint("\nEntered debugger on %s-chance exception (Exception Code: 0x%x) (%s)\n",
1574 FirstChance
? "first" : "last", ExceptionCode
, ExceptionString
);
1576 if (ExceptionCode
== STATUS_ACCESS_VIOLATION
&&
1577 ExceptionRecord
&& ExceptionRecord
->NumberParameters
!= 0)
1579 /* FIXME: Add noexec memory stuff */
1583 TrapCr2
= __readcr2();
1585 Err
= TrapFrame
->ErrCode
;
1586 KdbpPrint("Memory at 0x%p could not be %s: ", TrapCr2
, (Err
& (1 << 1)) ? "written" : "read");
1588 if ((Err
& (1 << 0)) == 0)
1590 KdbpPrint("Page not present.\n");
1594 if ((Err
& (1 << 3)) != 0)
1595 KdbpPrint("Reserved bits in page directory set.\n");
1597 KdbpPrint("Page protection violation.\n");
1602 /* Once we enter the debugger we do not expect any more single steps to happen */
1603 KdbNumSingleSteps
= 0;
1605 /* Update the current process pointer */
1606 KdbCurrentProcess
= KdbOriginalProcess
= PsGetCurrentProcess();
1607 KdbCurrentThread
= KdbOriginalThread
= PsGetCurrentThread();
1608 KdbCurrentTrapFrame
= &KdbTrapFrame
;
1610 /* Setup the KDB trap frame */
1611 KdbpTrapFrameToKdbTrapFrame(TrapFrame
, &KdbTrapFrame
);
1613 /* Enter critical section */
1614 OldEflags
= __readeflags();
1617 /* HACK: Save the current IRQL and pretend we are at passive level,
1618 * although interrupts are off. Needed because KDBG calls pageable code. */
1619 OldIrql
= KeGetCurrentIrql();
1620 KeLowerIrql(PASSIVE_LEVEL
);
1622 /* Exception inside the debugger? Game over. */
1623 if (InterlockedIncrement(&KdbEntryCount
) > 1)
1625 __writeeflags(OldEflags
);
1626 return kdHandleException
;
1629 /* Call the main loop. */
1630 KdbpInternalEnter();
1632 /* Check if we should single step */
1633 if (KdbNumSingleSteps
> 0)
1635 /* Variable explains itself! */
1636 KdbpEvenThoughWeHaveABreakPointToReenableWeAlsoHaveARealSingleStep
= TRUE
;
1638 if ((KdbSingleStepOver
&& KdbpStepOverInstruction(KdbCurrentTrapFrame
->Tf
.Eip
)) ||
1639 (!KdbSingleStepOver
&& KdbpStepIntoInstruction(KdbCurrentTrapFrame
->Tf
.Eip
)))
1641 ASSERT((KdbCurrentTrapFrame
->Tf
.EFlags
& EFLAGS_TF
) == 0);
1642 /*KdbCurrentTrapFrame->Tf.EFlags &= ~EFLAGS_TF;*/
1646 Context
->EFlags
|= EFLAGS_TF
;
1650 /* We can't update the current thread's trapframe 'cause it might not have one */
1652 /* Detach from attached process */
1653 if (KdbCurrentProcess
!= KdbOriginalProcess
)
1655 KeUnstackDetachProcess(&KdbApcState
);
1658 /* Update the exception TrapFrame */
1659 KdbpKdbTrapFrameToTrapFrame(&KdbTrapFrame
, TrapFrame
);
1661 /* Decrement the entry count */
1662 InterlockedDecrement(&KdbEntryCount
);
1664 /* HACK: Raise back to old IRQL */
1665 KeRaiseIrql(OldIrql
, &OldIrql
);
1667 /* Leave critical section */
1668 __writeeflags(OldEflags
);
1670 /* Check if user requested a bugcheck */
1671 if (KdbpBugCheckRequested
)
1673 /* Clear the flag and bugcheck the system */
1674 KdbpBugCheckRequested
= FALSE
;
1675 KeBugCheck(MANUALLY_INITIATED_CRASH
);
1679 /* Clear debug status */
1680 if (ExceptionCode
== STATUS_BREAKPOINT
) /* FIXME: Why clear DR6 on INT3? */
1682 /* Set the RF flag so we don't trigger the same breakpoint again. */
1685 TrapFrame
->EFlags
|= EFLAGS_RF
;
1688 /* Clear dr6 status flags. */
1689 TrapFrame
->Dr6
&= ~0x0000e00f;
1691 if (!(KdbEnteredOnSingleStep
&& KdbSingleStepOver
))
1693 /* Skip the current instruction */
1698 return ContinueType
;
1704 KdbpGetCommandLineSettings(
1707 #define CONST_STR_LEN(x) (sizeof(x)/sizeof(x[0]) - 1)
1709 while (p1
&& (p1
= strchr(p1
, ' ')))
1711 /* Skip other spaces */
1712 while (*p1
== ' ') ++p1
;
1714 if (!_strnicmp(p1
, "KDSERIAL", CONST_STR_LEN("KDSERIAL")))
1716 p1
+= CONST_STR_LEN("KDSERIAL");
1717 KdbDebugState
|= KD_DEBUG_KDSERIAL
;
1718 KdpDebugMode
.Serial
= TRUE
;
1720 else if (!_strnicmp(p1
, "KDNOECHO", CONST_STR_LEN("KDNOECHO")))
1722 p1
+= CONST_STR_LEN("KDNOECHO");
1723 KdbDebugState
|= KD_DEBUG_KDNOECHO
;
1725 else if (!_strnicmp(p1
, "FIRSTCHANCE", CONST_STR_LEN("FIRSTCHANCE")))
1727 p1
+= CONST_STR_LEN("FIRSTCHANCE");
1728 KdbpSetEnterCondition(-1, TRUE
, KdbEnterAlways
);
1739 BOOLEAN Result
= TRUE
;
1747 Result
= KdpSafeReadMemory((ULONG_PTR
)Src
, Bytes
, Dest
);
1752 ULONG_PTR Start
, End
, Write
;
1754 for (Start
= (ULONG_PTR
)Src
,
1755 End
= Start
+ Bytes
,
1756 Write
= (ULONG_PTR
)Dest
;
1757 Result
&& (Start
< End
);
1759 if (!KdpSafeReadMemory(Start
, 1, (PVOID
)Write
))
1766 return Result
? STATUS_SUCCESS
: STATUS_ACCESS_VIOLATION
;
1770 KdbpSafeWriteMemory(
1775 BOOLEAN Result
= TRUE
;
1776 ULONG_PTR Start
, End
, Write
;
1778 for (Start
= (ULONG_PTR
)Src
,
1779 End
= Start
+ Bytes
,
1780 Write
= (ULONG_PTR
)Dest
;
1781 Result
&& (Start
< End
);
1783 if (!KdpSafeWriteMemory(Write
, 1, *((PCHAR
)Start
)))
1786 return Result
? STATUS_SUCCESS
: STATUS_ACCESS_VIOLATION
;