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 ULONG TrapCr0
, TrapCr2
, TrapCr3
, TrapCr4
;
142 /* Copy the TrapFrame only up to Eflags and zero the rest*/
143 RtlCopyMemory(&KdbTrapFrame
->Tf
, TrapFrame
, FIELD_OFFSET(KTRAP_FRAME
, HardwareEsp
));
144 RtlZeroMemory((PVOID
)((ULONG_PTR
)&KdbTrapFrame
->Tf
+ FIELD_OFFSET(KTRAP_FRAME
, HardwareEsp
)),
145 sizeof(KTRAP_FRAME
) - FIELD_OFFSET(KTRAP_FRAME
, HardwareEsp
));
149 "movl %%cr0, %0" "\n\t"
150 "movl %%cr2, %1" "\n\t"
151 "movl %%cr3, %2" "\n\t"
152 "movl %%cr4, %3" "\n\t"
153 : "=r"(TrapCr0
), "=r"(TrapCr2
),
154 "=r"(TrapCr3
), "=r"(TrapCr4
));
166 /* FIXME: What's the problem with cr4? */
172 KdbTrapFrame
->Cr0
= TrapCr0
;
173 KdbTrapFrame
->Cr2
= TrapCr2
;
174 KdbTrapFrame
->Cr3
= TrapCr3
;
175 KdbTrapFrame
->Cr4
= TrapCr4
;
177 KdbTrapFrame
->Tf
.HardwareEsp
= KiEspFromTrapFrame(TrapFrame
);
178 KdbTrapFrame
->Tf
.HardwareSegSs
= (USHORT
)(KiSsFromTrapFrame(TrapFrame
) & 0xFFFF);
181 /* FIXME: copy v86 registers if TrapFrame is a V86 trapframe */
185 KdbpKdbTrapFrameToTrapFrame(
186 PKDB_KTRAP_FRAME KdbTrapFrame
,
187 PKTRAP_FRAME TrapFrame
)
189 /* Copy the TrapFrame only up to Eflags and zero the rest*/
190 RtlCopyMemory(TrapFrame
, &KdbTrapFrame
->Tf
, FIELD_OFFSET(KTRAP_FRAME
, HardwareEsp
));
192 /* FIXME: write cr0, cr2, cr3 and cr4 (not needed atm) */
194 KiSsToTrapFrame(TrapFrame
, KdbTrapFrame
->Tf
.HardwareSegSs
);
195 KiEspToTrapFrame(TrapFrame
, KdbTrapFrame
->Tf
.HardwareEsp
);
197 /* FIXME: copy v86 registers if TrapFrame is a V86 trapframe */
201 KdbpKdbTrapFrameFromKernelStack(
203 PKDB_KTRAP_FRAME KdbTrapFrame
)
207 RtlZeroMemory(KdbTrapFrame
, sizeof(KDB_KTRAP_FRAME
));
208 StackPtr
= (ULONG_PTR
*) KernelStack
;
210 KdbTrapFrame
->Tf
.Ebp
= StackPtr
[3];
211 KdbTrapFrame
->Tf
.Edi
= StackPtr
[4];
212 KdbTrapFrame
->Tf
.Esi
= StackPtr
[5];
213 KdbTrapFrame
->Tf
.Ebx
= StackPtr
[6];
214 KdbTrapFrame
->Tf
.Eip
= StackPtr
[7];
215 KdbTrapFrame
->Tf
.HardwareEsp
= (ULONG
) (StackPtr
+ 8);
216 KdbTrapFrame
->Tf
.HardwareSegSs
= KGDT_R0_DATA
;
217 KdbTrapFrame
->Tf
.SegCs
= KGDT_R0_CODE
;
218 KdbTrapFrame
->Tf
.SegDs
= KGDT_R0_DATA
;
219 KdbTrapFrame
->Tf
.SegEs
= KGDT_R0_DATA
;
220 KdbTrapFrame
->Tf
.SegGs
= KGDT_R0_DATA
;
223 /* FIXME: what about the other registers??? */
226 /*!\brief Overwrites the instruction at \a Address with \a NewInst and stores
227 * the old instruction in *OldInst.
229 * \param Process Process in which's context to overwrite the instruction.
230 * \param Address Address at which to overwrite the instruction.
231 * \param NewInst New instruction (written to \a Address)
232 * \param OldInst Old instruction (read from \a Address)
237 KdbpOverwriteInstruction(
238 IN PEPROCESS Process
,
239 IN ULONG_PTR Address
,
241 OUT PUCHAR OldInst OPTIONAL
)
245 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
248 /* Get the protection for the address. */
249 Protect
= MmGetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
));
251 /* Return if that page isn't present. */
252 if (Protect
& PAGE_NOACCESS
)
254 return STATUS_MEMORY_NOT_ALLOCATED
;
257 /* Attach to the process */
258 if (CurrentProcess
!= Process
)
260 KeStackAttachProcess(&Process
->Pcb
, &ApcState
);
263 /* Make the page writeable if it is read only. */
264 if (Protect
& (PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
))
266 MmSetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
),
267 (Protect
& ~(PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
)) | PAGE_READWRITE
);
270 /* Copy the old instruction back to the caller. */
273 Status
= KdbpSafeReadMemory(OldInst
, (PUCHAR
)Address
, 1);
274 if (!NT_SUCCESS(Status
))
276 if (Protect
& (PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
))
278 MmSetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
), Protect
);
281 /* Detach from process */
282 if (CurrentProcess
!= Process
)
291 /* Copy the new instruction in its place. */
292 Status
= KdbpSafeWriteMemory((PUCHAR
)Address
, &NewInst
, 1);
294 /* Restore the page protection. */
295 if (Protect
& (PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
))
297 MmSetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
), Protect
);
300 /* Detach from process */
301 if (CurrentProcess
!= Process
)
303 KeUnstackDetachProcess(&ApcState
);
309 /*!\brief Checks whether the given instruction can be single stepped or has to be
310 * stepped over using a temporary breakpoint.
312 * \retval TRUE Instruction is a call.
313 * \retval FALSE Instruction is not a call.
316 KdbpShouldStepOverInstruction(
322 if (!NT_SUCCESS(KdbpSafeReadMemory(Mem
, (PVOID
)Eip
, sizeof (Mem
))))
324 KdbpPrint("Couldn't access memory at 0x%p\n", Eip
);
328 /* Check if the current instruction is a call. */
329 while ((i
< sizeof (Mem
)) && (Mem
[i
] == 0x66 || Mem
[i
] == 0x67))
332 if (i
== sizeof (Mem
))
335 if (Mem
[i
] == 0xE8 || Mem
[i
] == 0x9A || Mem
[i
] == 0xF2 || Mem
[i
] == 0xF3 ||
336 (((i
+ 1) < sizeof (Mem
)) && Mem
[i
] == 0xFF && (Mem
[i
+1] & 0x38) == 0x10))
344 /*!\brief Steps over an instruction
346 * If the given instruction should be stepped over, this function inserts a
347 * temporary breakpoint after the instruction and returns TRUE, otherwise it
350 * \retval TRUE Temporary breakpoint set after instruction.
351 * \retval FALSE No breakpoint was set.
354 KdbpStepOverInstruction(
359 if (!KdbpShouldStepOverInstruction(Eip
))
362 InstLen
= KdbpGetInstLength(Eip
);
366 if (!NT_SUCCESS(KdbpInsertBreakPoint(Eip
+ InstLen
, KdbBreakPointTemporary
, 0, 0, NULL
, FALSE
, NULL
)))
372 /*!\brief Steps into an instruction (interrupts)
374 * If the given instruction should be stepped into, this function inserts a
375 * temporary breakpoint at the target instruction and returns TRUE, otherwise it
378 * \retval TRUE Temporary breakpoint set at target instruction.
379 * \retval FALSE No breakpoint was set.
382 KdbpStepIntoInstruction(
385 KDESCRIPTOR Idtr
= {0};
392 if (!NT_SUCCESS(KdbpSafeReadMemory(Mem
, (PVOID
)Eip
, sizeof (Mem
))))
394 /*KdbpPrint("Couldn't access memory at 0x%p\n", Eip);*/
398 /* Check for INT instruction */
399 /* FIXME: Check for iret */
402 else if (Mem
[0] == 0xcd)
404 else if (Mem
[0] == 0xce && KdbCurrentTrapFrame
->Tf
.EFlags
& (1<<11)) /* 1 << 11 is the overflow flag */
409 if (IntVect
< 32) /* We should be informed about interrupts < 32 by the kernel, no need to breakpoint them */
414 /* Read the interrupt descriptor table register */
416 if (IntVect
>= (Idtr
.Limit
+ 1) / 8)
418 /*KdbpPrint("IDT does not contain interrupt vector %d\n.", IntVect);*/
422 /* Get the interrupt descriptor */
423 if (!NT_SUCCESS(KdbpSafeReadMemory(IntDesc
, (PVOID
)(ULONG_PTR
)(Idtr
.Base
+ (IntVect
* 8)), sizeof (IntDesc
))))
425 /*KdbpPrint("Couldn't access memory at 0x%p\n", (ULONG_PTR)Idtr.Base + (IntVect * 8));*/
429 /* Check descriptor and get target eip (16 bit interrupt/trap gates not supported) */
430 if ((IntDesc
[1] & (1 << 15)) == 0) /* not present */
434 if ((IntDesc
[1] & 0x1f00) == 0x0500) /* Task gate */
436 /* FIXME: Task gates not supported */
439 else if (((IntDesc
[1] & 0x1fe0) == 0x0e00) || /* 32 bit Interrupt gate */
440 ((IntDesc
[1] & 0x1fe0) == 0x0f00)) /* 32 bit Trap gate */
442 /* FIXME: Should the segment selector of the interrupt gate be checked? */
443 TargetEip
= (IntDesc
[1] & 0xffff0000) | (IntDesc
[0] & 0x0000ffff);
450 /* Insert breakpoint */
451 if (!NT_SUCCESS(KdbpInsertBreakPoint(TargetEip
, KdbBreakPointTemporary
, 0, 0, NULL
, FALSE
, NULL
)))
457 /*!\brief Gets the number of the next breakpoint >= Start.
459 * \param Start Breakpoint number to start searching at. -1 if no more breakpoints are found.
461 * \returns Breakpoint number (-1 if no more breakpoints are found)
464 KdbpGetNextBreakPointNr(
465 IN ULONG Start OPTIONAL
)
467 for (; Start
< RTL_NUMBER_OF(KdbBreakPoints
); Start
++)
469 if (KdbBreakPoints
[Start
].Type
!= KdbBreakPointNone
)
476 /*!\brief Returns information of the specified breakpoint.
478 * \param BreakPointNr Number of the breakpoint to return information of.
479 * \param Address Receives the address of the breakpoint.
480 * \param Type Receives the type of the breakpoint (hardware or software)
481 * \param Size Size - for memory breakpoints.
482 * \param AccessType Access type - for hardware breakpoints.
483 * \param DebugReg Debug register - for enabled hardware breakpoints.
484 * \param Enabled Whether the breakpoint is enabled or not.
485 * \param Process The owning process of the breakpoint.
486 * \param ConditionExpression The expression which was given as condition for the bp.
488 * \returns NULL on failure, pointer to a KDB_BREAKPOINT struct on success.
491 KdbpGetBreakPointInfo(
492 IN ULONG BreakPointNr
,
493 OUT ULONG_PTR
*Address OPTIONAL
,
494 OUT KDB_BREAKPOINT_TYPE
*Type OPTIONAL
,
495 OUT UCHAR
*Size OPTIONAL
,
496 OUT KDB_ACCESS_TYPE
*AccessType OPTIONAL
,
497 OUT UCHAR
*DebugReg OPTIONAL
,
498 OUT BOOLEAN
*Enabled OPTIONAL
,
499 OUT BOOLEAN
*Global OPTIONAL
,
500 OUT PEPROCESS
*Process OPTIONAL
,
501 OUT PCHAR
*ConditionExpression OPTIONAL
)
505 if (BreakPointNr
>= RTL_NUMBER_OF(KdbBreakPoints
) ||
506 KdbBreakPoints
[BreakPointNr
].Type
== KdbBreakPointNone
)
511 bp
= KdbBreakPoints
+ BreakPointNr
;
513 *Address
= bp
->Address
;
518 if (bp
->Type
== KdbBreakPointHardware
)
521 *Size
= bp
->Data
.Hw
.Size
;
524 *AccessType
= bp
->Data
.Hw
.AccessType
;
526 if (DebugReg
&& bp
->Enabled
)
527 *DebugReg
= bp
->Data
.Hw
.DebugReg
;
531 *Enabled
= bp
->Enabled
;
534 *Global
= bp
->Global
;
537 *Process
= bp
->Process
;
539 if (ConditionExpression
)
540 *ConditionExpression
= bp
->ConditionExpression
;
545 /*!\brief Inserts a breakpoint into the breakpoint array.
547 * The \a Process of the breakpoint is set to \a KdbCurrentProcess
549 * \param Address Address at which to set the breakpoint.
550 * \param Type Type of breakpoint (hardware or software)
551 * \param Size Size of breakpoint (for hardware/memory breakpoints)
552 * \param AccessType Access type (for hardware breakpoins)
553 * \param ConditionExpression Expression which must evaluate to true for conditional breakpoints.
554 * \param Global Wether the breakpoint is global or local to a process.
555 * \param BreakPointNumber Receives the breakpoint number on success
560 KdbpInsertBreakPoint(
561 IN ULONG_PTR Address
,
562 IN KDB_BREAKPOINT_TYPE Type
,
563 IN UCHAR Size OPTIONAL
,
564 IN KDB_ACCESS_TYPE AccessType OPTIONAL
,
565 IN PCHAR ConditionExpression OPTIONAL
,
567 OUT PLONG BreakPointNr OPTIONAL
)
571 PCHAR ConditionExpressionDup
;
575 ASSERT(Type
!= KdbBreakPointNone
);
577 if (Type
== KdbBreakPointHardware
)
579 if ((Address
% Size
) != 0)
581 KdbpPrint("Address (0x%p) must be aligned to a multiple of the size (%d)\n", Address
, Size
);
582 return STATUS_UNSUCCESSFUL
;
585 if (AccessType
== KdbAccessExec
&& Size
!= 1)
587 KdbpPrint("Size must be 1 for execution breakpoints.\n");
588 return STATUS_UNSUCCESSFUL
;
592 if (KdbBreakPointCount
== KDB_MAXIMUM_BREAKPOINT_COUNT
)
594 return STATUS_UNSUCCESSFUL
;
597 /* Parse conditon expression string and duplicate it */
598 if (ConditionExpression
)
600 Condition
= KdbpRpnParseExpression(ConditionExpression
, &ErrOffset
, ErrMsg
);
604 KdbpPrint("Couldn't parse expression: %s at character %d\n", ErrMsg
, ErrOffset
);
606 KdbpPrint("Couldn't parse expression: %s", ErrMsg
);
608 return STATUS_UNSUCCESSFUL
;
611 i
= strlen(ConditionExpression
) + 1;
612 ConditionExpressionDup
= ExAllocatePoolWithTag(NonPagedPool
, i
, TAG_KDBG
);
613 RtlCopyMemory(ConditionExpressionDup
, ConditionExpression
, i
);
618 ConditionExpressionDup
= NULL
;
621 /* Find unused breakpoint */
622 if (Type
== KdbBreakPointTemporary
)
624 for (i
= RTL_NUMBER_OF(KdbBreakPoints
) - 1; i
>= 0; i
--)
626 if (KdbBreakPoints
[i
].Type
== KdbBreakPointNone
)
632 for (i
= 0; i
< (LONG
)RTL_NUMBER_OF(KdbBreakPoints
); i
++)
634 if (KdbBreakPoints
[i
].Type
== KdbBreakPointNone
)
639 ASSERT(i
< (LONG
)RTL_NUMBER_OF(KdbBreakPoints
));
641 /* Set the breakpoint */
642 ASSERT(KdbCurrentProcess
);
643 KdbBreakPoints
[i
].Type
= Type
;
644 KdbBreakPoints
[i
].Address
= Address
;
645 KdbBreakPoints
[i
].Enabled
= FALSE
;
646 KdbBreakPoints
[i
].Global
= Global
;
647 KdbBreakPoints
[i
].Process
= KdbCurrentProcess
;
648 KdbBreakPoints
[i
].ConditionExpression
= ConditionExpressionDup
;
649 KdbBreakPoints
[i
].Condition
= Condition
;
651 if (Type
== KdbBreakPointHardware
)
653 KdbBreakPoints
[i
].Data
.Hw
.Size
= Size
;
654 KdbBreakPoints
[i
].Data
.Hw
.AccessType
= AccessType
;
657 KdbBreakPointCount
++;
659 if (Type
!= KdbBreakPointTemporary
)
660 KdbpPrint("Breakpoint %d inserted.\n", i
);
662 /* Try to enable the breakpoint */
663 KdbpEnableBreakPoint(i
, NULL
);
665 /* Return the breakpoint number */
669 return STATUS_SUCCESS
;
672 /*!\brief Deletes a breakpoint
674 * \param BreakPointNr Number of the breakpoint to delete. Can be -1
675 * \param BreakPoint Breakpoint to delete. Can be NULL.
677 * \retval TRUE Success.
678 * \retval FALSE Failure (invalid breakpoint number)
681 KdbpDeleteBreakPoint(
682 IN LONG BreakPointNr OPTIONAL
,
683 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL
)
685 if (BreakPointNr
< 0)
688 BreakPointNr
= BreakPoint
- KdbBreakPoints
;
691 if (BreakPointNr
< 0 || BreakPointNr
>= KDB_MAXIMUM_BREAKPOINT_COUNT
)
693 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
699 BreakPoint
= KdbBreakPoints
+ BreakPointNr
;
702 if (BreakPoint
->Type
== KdbBreakPointNone
)
704 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
708 if (BreakPoint
->Enabled
&& !KdbpDisableBreakPoint(-1, BreakPoint
))
711 if (BreakPoint
->Type
!= KdbBreakPointTemporary
)
712 KdbpPrint("Breakpoint %d deleted.\n", BreakPointNr
);
714 BreakPoint
->Type
= KdbBreakPointNone
;
715 KdbBreakPointCount
--;
720 /*!\brief Checks if the breakpoint was set by the debugger
722 * Tries to find a breakpoint in the breakpoint array which caused
723 * the debug exception to happen.
725 * \param ExpNr Exception Number (1 or 3)
726 * \param TrapFrame Exception trapframe
728 * \returns Breakpoint number, -1 on error.
731 KdbpIsBreakPointOurs(
732 IN NTSTATUS ExceptionCode
,
733 IN PKTRAP_FRAME TrapFrame
)
736 ASSERT(ExceptionCode
== STATUS_SINGLE_STEP
|| ExceptionCode
== STATUS_BREAKPOINT
);
738 if (ExceptionCode
== STATUS_BREAKPOINT
) /* Software interrupt */
740 ULONG_PTR BpEip
= (ULONG_PTR
)TrapFrame
->Eip
- 1; /* Get EIP of INT3 instruction */
741 for (i
= 0; i
< KdbSwBreakPointCount
; i
++)
743 ASSERT((KdbSwBreakPoints
[i
]->Type
== KdbBreakPointSoftware
||
744 KdbSwBreakPoints
[i
]->Type
== KdbBreakPointTemporary
));
745 ASSERT(KdbSwBreakPoints
[i
]->Enabled
);
747 if (KdbSwBreakPoints
[i
]->Address
== BpEip
)
749 return KdbSwBreakPoints
[i
] - KdbBreakPoints
;
753 else if (ExceptionCode
== STATUS_SINGLE_STEP
) /* Hardware interrupt */
757 for (i
= 0; i
< KdbHwBreakPointCount
; i
++)
759 ASSERT(KdbHwBreakPoints
[i
]->Type
== KdbBreakPointHardware
&&
760 KdbHwBreakPoints
[i
]->Enabled
);
761 DebugReg
= KdbHwBreakPoints
[i
]->Data
.Hw
.DebugReg
;
763 if ((TrapFrame
->Dr6
& (1 << DebugReg
)) != 0)
765 return KdbHwBreakPoints
[i
] - KdbBreakPoints
;
773 /*!\brief Enables a breakpoint.
775 * \param BreakPointNr Number of the breakpoint to enable Can be -1.
776 * \param BreakPoint Breakpoint to enable. Can be NULL.
778 * \retval TRUE Success.
779 * \retval FALSE Failure.
781 * \sa KdbpDisableBreakPoint
784 KdbpEnableBreakPoint(
785 IN LONG BreakPointNr OPTIONAL
,
786 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL
)
792 if (BreakPointNr
< 0)
795 BreakPointNr
= BreakPoint
- KdbBreakPoints
;
798 if (BreakPointNr
< 0 || BreakPointNr
>= KDB_MAXIMUM_BREAKPOINT_COUNT
)
800 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
806 BreakPoint
= KdbBreakPoints
+ BreakPointNr
;
809 if (BreakPoint
->Type
== KdbBreakPointNone
)
811 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
815 if (BreakPoint
->Enabled
)
817 KdbpPrint("Breakpoint %d is already enabled.\n", BreakPointNr
);
821 if (BreakPoint
->Type
== KdbBreakPointSoftware
||
822 BreakPoint
->Type
== KdbBreakPointTemporary
)
824 if (KdbSwBreakPointCount
>= KDB_MAXIMUM_SW_BREAKPOINT_COUNT
)
826 KdbpPrint("Maximum number of SW breakpoints (%d) used. "
827 "Disable another breakpoint in order to enable this one.\n",
828 KDB_MAXIMUM_SW_BREAKPOINT_COUNT
);
832 Status
= KdbpOverwriteInstruction(BreakPoint
->Process
, BreakPoint
->Address
,
833 0xCC, &BreakPoint
->Data
.SavedInstruction
);
834 if (!NT_SUCCESS(Status
))
836 KdbpPrint("Couldn't access memory at 0x%p\n", BreakPoint
->Address
);
840 KdbSwBreakPoints
[KdbSwBreakPointCount
++] = BreakPoint
;
844 if (BreakPoint
->Data
.Hw
.AccessType
== KdbAccessExec
)
845 ASSERT(BreakPoint
->Data
.Hw
.Size
== 1);
847 ASSERT((BreakPoint
->Address
% BreakPoint
->Data
.Hw
.Size
) == 0);
849 if (KdbHwBreakPointCount
>= KDB_MAXIMUM_HW_BREAKPOINT_COUNT
)
851 KdbpPrint("Maximum number of HW breakpoints (%d) already used. "
852 "Disable another breakpoint in order to enable this one.\n",
853 KDB_MAXIMUM_HW_BREAKPOINT_COUNT
);
858 /* Find unused hw breakpoint */
859 ASSERT(KDB_MAXIMUM_HW_BREAKPOINT_COUNT
== 4);
860 for (i
= 0; i
< KDB_MAXIMUM_HW_BREAKPOINT_COUNT
; i
++)
862 if ((KdbTrapFrame
.Tf
.Dr7
& (0x3 << (i
* 2))) == 0)
866 ASSERT(i
< KDB_MAXIMUM_HW_BREAKPOINT_COUNT
);
868 /* Set the breakpoint address. */
872 KdbTrapFrame
.Tf
.Dr0
= BreakPoint
->Address
;
875 KdbTrapFrame
.Tf
.Dr1
= BreakPoint
->Address
;
878 KdbTrapFrame
.Tf
.Dr2
= BreakPoint
->Address
;
881 KdbTrapFrame
.Tf
.Dr3
= BreakPoint
->Address
;
885 /* Enable the global breakpoint */
886 KdbTrapFrame
.Tf
.Dr7
|= (0x2 << (i
* 2));
888 /* Enable the exact match bits. */
889 KdbTrapFrame
.Tf
.Dr7
|= 0x00000300;
891 /* Clear existing state. */
892 KdbTrapFrame
.Tf
.Dr7
&= ~(0xF << (16 + (i
* 4)));
894 /* Set the breakpoint type. */
895 switch (BreakPoint
->Data
.Hw
.AccessType
)
904 case KdbAccessReadWrite
:
913 KdbTrapFrame
.Tf
.Dr7
|= (ul
<< (16 + (i
* 4)));
915 /* Set the breakpoint length. */
916 KdbTrapFrame
.Tf
.Dr7
|= ((BreakPoint
->Data
.Hw
.Size
- 1) << (18 + (i
* 4)));
918 /* Update KdbCurrentTrapFrame - values are taken from there by the CLI */
919 if (&KdbTrapFrame
!= KdbCurrentTrapFrame
)
921 KdbCurrentTrapFrame
->Tf
.Dr0
= KdbTrapFrame
.Tf
.Dr0
;
922 KdbCurrentTrapFrame
->Tf
.Dr1
= KdbTrapFrame
.Tf
.Dr1
;
923 KdbCurrentTrapFrame
->Tf
.Dr2
= KdbTrapFrame
.Tf
.Dr2
;
924 KdbCurrentTrapFrame
->Tf
.Dr3
= KdbTrapFrame
.Tf
.Dr3
;
925 KdbCurrentTrapFrame
->Tf
.Dr6
= KdbTrapFrame
.Tf
.Dr6
;
926 KdbCurrentTrapFrame
->Tf
.Dr7
= KdbTrapFrame
.Tf
.Dr7
;
929 BreakPoint
->Data
.Hw
.DebugReg
= i
;
930 KdbHwBreakPoints
[KdbHwBreakPointCount
++] = BreakPoint
;
933 BreakPoint
->Enabled
= TRUE
;
934 if (BreakPoint
->Type
!= KdbBreakPointTemporary
)
935 KdbpPrint("Breakpoint %d enabled.\n", BreakPointNr
);
940 /*!\brief Disables a breakpoint.
942 * \param BreakPointNr Number of the breakpoint to disable. Can be -1
943 * \param BreakPoint Breakpoint to disable. Can be NULL.
945 * \retval TRUE Success.
946 * \retval FALSE Failure.
948 * \sa KdbpEnableBreakPoint
951 KdbpDisableBreakPoint(
952 IN LONG BreakPointNr OPTIONAL
,
953 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL
)
958 if (BreakPointNr
< 0)
961 BreakPointNr
= BreakPoint
- KdbBreakPoints
;
964 if (BreakPointNr
< 0 || BreakPointNr
>= KDB_MAXIMUM_BREAKPOINT_COUNT
)
966 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
972 BreakPoint
= KdbBreakPoints
+ BreakPointNr
;
975 if (BreakPoint
->Type
== KdbBreakPointNone
)
977 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
981 if (BreakPoint
->Enabled
== FALSE
)
983 KdbpPrint("Breakpoint %d is not enabled.\n", BreakPointNr
);
987 if (BreakPoint
->Type
== KdbBreakPointSoftware
||
988 BreakPoint
->Type
== KdbBreakPointTemporary
)
990 ASSERT(KdbSwBreakPointCount
> 0);
991 Status
= KdbpOverwriteInstruction(BreakPoint
->Process
, BreakPoint
->Address
,
992 BreakPoint
->Data
.SavedInstruction
, NULL
);
994 if (!NT_SUCCESS(Status
))
996 KdbpPrint("Couldn't restore original instruction.\n");
1000 for (i
= 0; i
< KdbSwBreakPointCount
; i
++)
1002 if (KdbSwBreakPoints
[i
] == BreakPoint
)
1004 KdbSwBreakPoints
[i
] = KdbSwBreakPoints
[--KdbSwBreakPointCount
];
1005 i
= -1; /* if the last breakpoint is disabled dont break with i >= KdbSwBreakPointCount */
1010 if (i
!= MAXULONG
) /* not found */
1015 ASSERT(BreakPoint
->Type
== KdbBreakPointHardware
);
1017 /* Clear the breakpoint. */
1018 KdbTrapFrame
.Tf
.Dr7
&= ~(0x3 << (BreakPoint
->Data
.Hw
.DebugReg
* 2));
1019 if ((KdbTrapFrame
.Tf
.Dr7
& 0xFF) == 0)
1021 /* If no breakpoints are enabled then clear the exact match flags. */
1022 KdbTrapFrame
.Tf
.Dr7
&= 0xFFFFFCFF;
1025 for (i
= 0; i
< KdbHwBreakPointCount
; i
++)
1027 if (KdbHwBreakPoints
[i
] == BreakPoint
)
1029 KdbHwBreakPoints
[i
] = KdbHwBreakPoints
[--KdbHwBreakPointCount
];
1030 i
= -1; /* if the last breakpoint is disabled dont break with i >= KdbHwBreakPointCount */
1035 if (i
!= MAXULONG
) /* not found */
1039 BreakPoint
->Enabled
= FALSE
;
1040 if (BreakPoint
->Type
!= KdbBreakPointTemporary
)
1041 KdbpPrint("Breakpoint %d disabled.\n", BreakPointNr
);
1046 /*!\brief Gets the first or last chance enter-condition for exception nr. \a ExceptionNr
1048 * \param ExceptionNr Number of the exception to get condition of.
1049 * \param FirstChance Whether to get first or last chance condition.
1050 * \param Condition Receives the condition setting.
1052 * \retval TRUE Success.
1053 * \retval FALSE Failure (invalid exception nr)
1056 KdbpGetEnterCondition(
1057 IN LONG ExceptionNr
,
1058 IN BOOLEAN FirstChance
,
1059 OUT KDB_ENTER_CONDITION
*Condition
)
1061 if (ExceptionNr
>= (LONG
)RTL_NUMBER_OF(KdbEnterConditions
))
1064 *Condition
= KdbEnterConditions
[ExceptionNr
][FirstChance
? 0 : 1];
1068 /*!\brief Sets the first or last chance enter-condition for exception nr. \a ExceptionNr
1070 * \param ExceptionNr Number of the exception to set condition of (-1 for all)
1071 * \param FirstChance Whether to set first or last chance condition.
1072 * \param Condition The new condition setting.
1074 * \retval TRUE Success.
1075 * \retval FALSE Failure (invalid exception nr)
1078 KdbpSetEnterCondition(
1079 IN LONG ExceptionNr
,
1080 IN BOOLEAN FirstChance
,
1081 IN KDB_ENTER_CONDITION Condition
)
1083 if (ExceptionNr
< 0)
1085 for (ExceptionNr
= 0; ExceptionNr
< (LONG
)RTL_NUMBER_OF(KdbEnterConditions
); ExceptionNr
++)
1087 if (ExceptionNr
== 1 || ExceptionNr
== 8 ||
1088 ExceptionNr
== 9 || ExceptionNr
== 15) /* Reserved exceptions */
1093 KdbEnterConditions
[ExceptionNr
][FirstChance
? 0 : 1] = Condition
;
1098 if (ExceptionNr
>= (LONG
)RTL_NUMBER_OF(KdbEnterConditions
) ||
1099 ExceptionNr
== 1 || ExceptionNr
== 8 || /* Do not allow changing of the debug */
1100 ExceptionNr
== 9 || ExceptionNr
== 15) /* trap or reserved exceptions */
1105 KdbEnterConditions
[ExceptionNr
][FirstChance
? 0 : 1] = Condition
;
1111 /*!\brief Switches to another thread context
1113 * \param ThreadId Id of the thread to switch to.
1115 * \retval TRUE Success.
1116 * \retval FALSE Failure (i.e. invalid thread id)
1122 PETHREAD Thread
= NULL
;
1125 /* Get a pointer to the thread */
1126 if (!NT_SUCCESS(PsLookupThreadByThreadId(ThreadId
, &Thread
)))
1128 KdbpPrint("Invalid thread id: 0x%08x\n", (ULONG_PTR
)ThreadId
);
1131 Process
= Thread
->ThreadsProcess
;
1133 if (KeIsExecutingDpc() && Process
!= KdbCurrentProcess
)
1135 KdbpPrint("Cannot attach to thread within another process while executing a DPC.\n");
1136 ObDereferenceObject(Thread
);
1140 /* Save the current thread's context (if we previously attached to a thread) */
1141 if (KdbCurrentThread
!= KdbOriginalThread
)
1143 ASSERT(KdbCurrentTrapFrame
== &KdbThreadTrapFrame
);
1144 /* Actually, we can't save the context, there's no guarantee that there was a trap frame */
1148 ASSERT(KdbCurrentTrapFrame
== &KdbTrapFrame
);
1151 /* Switch to the thread's context */
1152 if (Thread
!= KdbOriginalThread
)
1154 /* The thread we're attaching to isn't the thread on which we entered
1155 * kdb and so the thread we're attaching to is not running. There
1156 * is no guarantee that it actually has a trap frame. So we have to
1157 * peek directly at the registers which were saved on the stack when the
1158 * thread was preempted in the scheduler */
1159 KdbpKdbTrapFrameFromKernelStack(Thread
->Tcb
.KernelStack
,
1160 &KdbThreadTrapFrame
);
1161 KdbCurrentTrapFrame
= &KdbThreadTrapFrame
;
1163 else /* Switching back to original thread */
1165 KdbCurrentTrapFrame
= &KdbTrapFrame
;
1167 KdbCurrentThread
= Thread
;
1169 /* Attach to the thread's process */
1170 ASSERT(KdbCurrentProcess
== PsGetCurrentProcess());
1171 if (KdbCurrentProcess
!= Process
)
1173 if (KdbCurrentProcess
!= KdbOriginalProcess
) /* detach from previously attached process */
1175 KeUnstackDetachProcess(&KdbApcState
);
1178 if (KdbOriginalProcess
!= Process
)
1180 KeStackAttachProcess(&Process
->Pcb
, &KdbApcState
);
1183 KdbCurrentProcess
= Process
;
1186 ObDereferenceObject(Thread
);
1190 /*!\brief Switches to another process/thread context
1192 * This function switches to the first thread in the specified process.
1194 * \param ProcessId Id of the process to switch to.
1196 * \retval TRUE Success.
1197 * \retval FALSE Failure (i.e. invalid process id)
1200 KdbpAttachToProcess(
1203 PEPROCESS Process
= NULL
;
1207 /* Get a pointer to the process */
1208 if (!NT_SUCCESS(PsLookupProcessByProcessId(ProcessId
, &Process
)))
1210 KdbpPrint("Invalid process id: 0x%08x\n", (ULONG_PTR
)ProcessId
);
1214 Entry
= Process
->ThreadListHead
.Flink
;
1215 ObDereferenceObject(Process
);
1216 if (Entry
== &KdbCurrentProcess
->ThreadListHead
)
1218 KdbpPrint("No threads in process 0x%p, cannot attach to process!\n", ProcessId
);
1222 Thread
= CONTAINING_RECORD(Entry
, ETHREAD
, ThreadListEntry
);
1224 return KdbpAttachToThread(Thread
->Cid
.UniqueThread
);
1227 /*!\brief Calls the main loop ...
1230 KdbpCallMainLoop(VOID
)
1232 KdbpCliMainLoop(KdbEnteredOnSingleStep
);
1235 /*!\brief Internal function to enter KDB.
1237 * Disables interrupts, releases display ownership, ...
1240 KdbpInternalEnter(VOID
)
1243 PVOID SavedInitialStack
, SavedStackBase
, SavedKernelStack
;
1244 ULONG SavedStackLimit
;
1248 if (KdpDebugMode
.Screen
&&
1249 InbvIsBootDriverInstalled() &&
1250 !InbvCheckDisplayOwnership())
1252 /* Acquire ownership and reset the display */
1253 InbvAcquireDisplayOwnership();
1256 /* Display debugger prompt */
1257 InbvSolidColorFill(0, 0, 639, 479, 0);
1258 InbvSetTextColor(15);
1259 InbvInstallDisplayStringFilter(NULL
);
1260 InbvEnableDisplayString(TRUE
);
1261 InbvSetScrollRegion(0, 0, 639, 479);
1264 /* Call the interface's main loop on a different stack */
1265 Thread
= PsGetCurrentThread();
1266 SavedInitialStack
= Thread
->Tcb
.InitialStack
;
1267 SavedStackBase
= Thread
->Tcb
.StackBase
;
1268 SavedStackLimit
= Thread
->Tcb
.StackLimit
;
1269 SavedKernelStack
= Thread
->Tcb
.KernelStack
;
1270 Thread
->Tcb
.InitialStack
= Thread
->Tcb
.StackBase
= (char*)KdbStack
+ KDB_STACK_SIZE
;
1271 Thread
->Tcb
.StackLimit
= (ULONG_PTR
)KdbStack
;
1272 Thread
->Tcb
.KernelStack
= (char*)KdbStack
+ KDB_STACK_SIZE
;
1274 /*KdbpPrint("Switching to KDB stack 0x%08x-0x%08x (Current Stack is 0x%08x)\n", Thread->Tcb.StackLimit, Thread->Tcb.StackBase, Esp);*/
1276 KdbpStackSwitchAndCall(KdbStack
+ KDB_STACK_SIZE
- sizeof(ULONG
), KdbpCallMainLoop
);
1278 Thread
->Tcb
.InitialStack
= SavedInitialStack
;
1279 Thread
->Tcb
.StackBase
= SavedStackBase
;
1280 Thread
->Tcb
.StackLimit
= SavedStackLimit
;
1281 Thread
->Tcb
.KernelStack
= SavedKernelStack
;
1286 KdbpGetExceptionNumberFromStatus(
1287 IN NTSTATUS ExceptionCode
)
1291 switch (ExceptionCode
)
1293 case STATUS_INTEGER_DIVIDE_BY_ZERO
:
1296 case STATUS_SINGLE_STEP
:
1299 case STATUS_BREAKPOINT
:
1302 case STATUS_INTEGER_OVERFLOW
:
1305 case STATUS_ARRAY_BOUNDS_EXCEEDED
:
1308 case STATUS_ILLEGAL_INSTRUCTION
:
1311 case STATUS_FLOAT_INVALID_OPERATION
:
1314 case STATUS_STACK_OVERFLOW
:
1317 case STATUS_ACCESS_VIOLATION
:
1320 case STATUS_DATATYPE_MISALIGNMENT
:
1323 case STATUS_FLOAT_MULTIPLE_TRAPS
:
1326 case STATUS_ASSERTION_FAILURE
:
1331 Ret
= RTL_NUMBER_OF(KdbEnterConditions
) - 1;
1338 /*!\brief KDB Exception filter
1340 * Called by the exception dispatcher.
1342 * \param ExceptionRecord Unused.
1343 * \param PreviousMode UserMode if the exception was raised from umode, otherwise KernelMode.
1344 * \param Context Context, IN/OUT parameter.
1345 * \param TrapFrame Exception TrapFrame.
1346 * \param FirstChance TRUE when called before exception frames were serached,
1347 * FALSE for the second call.
1349 * \returns KD_CONTINUE_TYPE
1352 KdbEnterDebuggerException(
1353 IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL
,
1354 IN KPROCESSOR_MODE PreviousMode
,
1355 IN PCONTEXT Context
,
1356 IN OUT PKTRAP_FRAME TrapFrame
,
1357 IN BOOLEAN FirstChance
)
1359 KDB_ENTER_CONDITION EnterCondition
;
1360 KD_CONTINUE_TYPE ContinueType
= kdHandleException
;
1361 PKDB_BREAKPOINT BreakPoint
;
1364 BOOLEAN Resume
= FALSE
;
1365 BOOLEAN EnterConditionMet
= TRUE
;
1368 NTSTATUS ExceptionCode
;
1370 ExceptionCode
= (ExceptionRecord
? ExceptionRecord
->ExceptionCode
: STATUS_BREAKPOINT
);
1372 KdbCurrentProcess
= PsGetCurrentProcess();
1374 /* Set continue type to kdContinue for single steps and breakpoints */
1375 if (ExceptionCode
== STATUS_SINGLE_STEP
||
1376 ExceptionCode
== STATUS_BREAKPOINT
||
1377 ExceptionCode
== STATUS_ASSERTION_FAILURE
)
1379 ContinueType
= kdContinue
;
1382 /* Check if we should handle the exception. */
1383 /* FIXME - won't get all exceptions here :( */
1384 ExpNr
= KdbpGetExceptionNumberFromStatus(ExceptionCode
);
1385 EnterCondition
= KdbEnterConditions
[ExpNr
][FirstChance
? 0 : 1];
1386 if (EnterCondition
== KdbDoNotEnter
||
1387 (EnterCondition
== KdbEnterFromUmode
&& PreviousMode
== KernelMode
) ||
1388 (EnterCondition
== KdbEnterFromKmode
&& PreviousMode
!= KernelMode
))
1390 EnterConditionMet
= FALSE
;
1393 /* If we stopped on one of our breakpoints then let the user know. */
1394 KdbLastBreakPointNr
= -1;
1395 KdbEnteredOnSingleStep
= FALSE
;
1397 if (FirstChance
&& (ExceptionCode
== STATUS_SINGLE_STEP
|| ExceptionCode
== STATUS_BREAKPOINT
) &&
1398 (KdbLastBreakPointNr
= KdbpIsBreakPointOurs(ExceptionCode
, TrapFrame
)) >= 0)
1400 BreakPoint
= KdbBreakPoints
+ KdbLastBreakPointNr
;
1402 if (ExceptionCode
== STATUS_BREAKPOINT
)
1404 /* ... and restore the original instruction. */
1405 if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess
, BreakPoint
->Address
,
1406 BreakPoint
->Data
.SavedInstruction
, NULL
)))
1408 KdbpPrint("Couldn't restore original instruction after INT3! Cannot continue execution.\n");
1409 KeBugCheck(0); // FIXME: Proper bugcode!
1412 /* Also since we are past the int3 now, decrement EIP in the
1413 TrapFrame. This is only needed because KDBG insists on working
1414 with the TrapFrame instead of with the Context, as it is supposed
1415 to do. The context has already EIP point to the int3, since
1416 KiDispatchException accounts for that. Whatever we do here with
1417 the TrapFrame does not matter anyway, since KiDispatchException
1418 will overwrite it with the values from the Context! */
1422 if ((BreakPoint
->Type
== KdbBreakPointHardware
) &&
1423 (BreakPoint
->Data
.Hw
.AccessType
== KdbAccessExec
))
1425 Resume
= TRUE
; /* Set the resume flag when continuing execution */
1429 * When a temporary breakpoint is hit we have to make sure that we are
1430 * in the same context in which it was set, otherwise it could happen
1431 * that another process/thread hits it before and it gets deleted.
1433 else if (BreakPoint
->Type
== KdbBreakPointTemporary
&&
1434 BreakPoint
->Process
== KdbCurrentProcess
)
1436 ASSERT((TrapFrame
->EFlags
& EFLAGS_TF
) == 0);
1438 /* Delete the temporary breakpoint which was used to step over or into the instruction. */
1439 KdbpDeleteBreakPoint(-1, BreakPoint
);
1441 if (--KdbNumSingleSteps
> 0)
1443 if ((KdbSingleStepOver
&& !KdbpStepOverInstruction(TrapFrame
->Eip
)) ||
1444 (!KdbSingleStepOver
&& !KdbpStepIntoInstruction(TrapFrame
->Eip
)))
1446 Context
->EFlags
|= EFLAGS_TF
;
1449 goto continue_execution
; /* return */
1452 KdbEnteredOnSingleStep
= TRUE
;
1456 * If we hit a breakpoint set by the debugger we set the single step flag,
1457 * ignore the next single step and reenable the breakpoint.
1459 else if (BreakPoint
->Type
== KdbBreakPointSoftware
||
1460 BreakPoint
->Type
== KdbBreakPointTemporary
)
1462 ASSERT(ExceptionCode
== STATUS_BREAKPOINT
);
1463 Context
->EFlags
|= EFLAGS_TF
;
1464 KdbBreakPointToReenable
= BreakPoint
;
1467 /* Make sure that the breakpoint should be triggered in this context */
1468 if (!BreakPoint
->Global
&& BreakPoint
->Process
!= KdbCurrentProcess
)
1470 goto continue_execution
; /* return */
1473 /* Check if the condition for the breakpoint is met. */
1474 if (BreakPoint
->Condition
)
1476 /* Setup the KDB trap frame */
1477 KdbpTrapFrameToKdbTrapFrame(TrapFrame
, &KdbTrapFrame
);
1480 if (!KdbpRpnEvaluateParsedExpression(BreakPoint
->Condition
, &KdbTrapFrame
, &ull
, NULL
, NULL
))
1482 /* FIXME: Print warning? */
1484 else if (ull
== 0) /* condition is not met */
1486 goto continue_execution
; /* return */
1490 if (BreakPoint
->Type
== KdbBreakPointSoftware
)
1492 KdbpPrint("\nEntered debugger on breakpoint #%d: EXEC 0x%04x:0x%08x\n",
1493 KdbLastBreakPointNr
, TrapFrame
->SegCs
& 0xffff, TrapFrame
->Eip
);
1495 else if (BreakPoint
->Type
== KdbBreakPointHardware
)
1497 KdbpPrint("\nEntered debugger on breakpoint #%d: %s 0x%08x\n",
1498 KdbLastBreakPointNr
,
1499 (BreakPoint
->Data
.Hw
.AccessType
== KdbAccessRead
) ? "READ" :
1500 ((BreakPoint
->Data
.Hw
.AccessType
== KdbAccessWrite
) ? "WRITE" :
1501 ((BreakPoint
->Data
.Hw
.AccessType
== KdbAccessReadWrite
) ? "RDWR" : "EXEC")),
1502 BreakPoint
->Address
);
1505 else if (ExceptionCode
== STATUS_SINGLE_STEP
)
1507 /* Silently ignore a debugger initiated single step. */
1508 if ((TrapFrame
->Dr6
& 0xf) == 0 && KdbBreakPointToReenable
)
1510 /* FIXME: Make sure that the breakpoint was really hit (check bp->Address vs. tf->Eip) */
1511 BreakPoint
= KdbBreakPointToReenable
;
1512 KdbBreakPointToReenable
= NULL
;
1513 ASSERT(BreakPoint
->Type
== KdbBreakPointSoftware
||
1514 BreakPoint
->Type
== KdbBreakPointTemporary
);
1517 * Reenable the breakpoint we disabled to execute the breakpointed
1520 if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess
, BreakPoint
->Address
, 0xCC,
1521 &BreakPoint
->Data
.SavedInstruction
)))
1523 KdbpPrint("Warning: Couldn't reenable breakpoint %d\n",
1524 BreakPoint
- KdbBreakPoints
);
1527 /* Unset TF if we are no longer single stepping. */
1528 if (KdbNumSingleSteps
== 0)
1529 Context
->EFlags
&= ~EFLAGS_TF
;
1531 if (!KdbpEvenThoughWeHaveABreakPointToReenableWeAlsoHaveARealSingleStep
)
1533 goto continue_execution
; /* return */
1537 /* Quoth the raven, 'Nevermore!' */
1538 KdbpEvenThoughWeHaveABreakPointToReenableWeAlsoHaveARealSingleStep
= FALSE
;
1540 /* Check if we expect a single step */
1541 if ((TrapFrame
->Dr6
& 0xf) == 0 && KdbNumSingleSteps
> 0)
1543 /*ASSERT((Context->Eflags & EFLAGS_TF) != 0);*/
1544 if (--KdbNumSingleSteps
> 0)
1546 if ((KdbSingleStepOver
&& KdbpStepOverInstruction(TrapFrame
->Eip
)) ||
1547 (!KdbSingleStepOver
&& KdbpStepIntoInstruction(TrapFrame
->Eip
)))
1549 Context
->EFlags
&= ~EFLAGS_TF
;
1553 Context
->EFlags
|= EFLAGS_TF
;
1556 goto continue_execution
; /* return */
1560 Context
->EFlags
&= ~EFLAGS_TF
;
1561 KdbEnteredOnSingleStep
= TRUE
;
1566 if (!EnterConditionMet
)
1568 return kdHandleException
;
1571 KdbpPrint("\nEntered debugger on unexpected debug trap!\n");
1574 else if (ExceptionCode
== STATUS_BREAKPOINT
)
1576 if (KdbInitFileBuffer
)
1578 KdbpCliInterpretInitFile();
1579 EnterConditionMet
= FALSE
;
1581 if (!EnterConditionMet
)
1583 return kdHandleException
;
1586 KdbpPrint("\nEntered debugger on embedded INT3 at 0x%04x:0x%08x.\n",
1587 TrapFrame
->SegCs
& 0xffff, TrapFrame
->Eip
- 1);
1591 const CHAR
*ExceptionString
= (ExpNr
< RTL_NUMBER_OF(ExceptionNrToString
)) ?
1592 (ExceptionNrToString
[ExpNr
]) :
1593 ("Unknown/User defined exception");
1595 if (!EnterConditionMet
)
1597 return ContinueType
;
1600 KdbpPrint("\nEntered debugger on %s-chance exception (Exception Code: 0x%x) (%s)\n",
1601 FirstChance
? "first" : "last", ExceptionCode
, ExceptionString
);
1603 if (ExceptionCode
== STATUS_ACCESS_VIOLATION
&&
1604 ExceptionRecord
&& ExceptionRecord
->NumberParameters
!= 0)
1606 /* FIXME: Add noexec memory stuff */
1610 TrapCr2
= __readcr2();
1612 Err
= TrapFrame
->ErrCode
;
1613 KdbpPrint("Memory at 0x%p could not be %s: ", TrapCr2
, (Err
& (1 << 1)) ? "written" : "read");
1615 if ((Err
& (1 << 0)) == 0)
1617 KdbpPrint("Page not present.\n");
1621 if ((Err
& (1 << 3)) != 0)
1622 KdbpPrint("Reserved bits in page directory set.\n");
1624 KdbpPrint("Page protection violation.\n");
1629 /* Once we enter the debugger we do not expect any more single steps to happen */
1630 KdbNumSingleSteps
= 0;
1632 /* Update the current process pointer */
1633 KdbCurrentProcess
= KdbOriginalProcess
= PsGetCurrentProcess();
1634 KdbCurrentThread
= KdbOriginalThread
= PsGetCurrentThread();
1635 KdbCurrentTrapFrame
= &KdbTrapFrame
;
1637 /* Setup the KDB trap frame */
1638 KdbpTrapFrameToKdbTrapFrame(TrapFrame
, &KdbTrapFrame
);
1640 /* Enter critical section */
1641 OldEflags
= __readeflags();
1644 /* HACK: Save the current IRQL and pretend we are at passive level,
1645 * although interrupts are off. Needed because KDBG calls pageable code. */
1646 OldIrql
= KeGetCurrentIrql();
1647 KeLowerIrql(PASSIVE_LEVEL
);
1649 /* Exception inside the debugger? Game over. */
1650 if (InterlockedIncrement(&KdbEntryCount
) > 1)
1652 __writeeflags(OldEflags
);
1653 return kdHandleException
;
1656 /* Call the main loop. */
1657 KdbpInternalEnter();
1659 /* Check if we should single step */
1660 if (KdbNumSingleSteps
> 0)
1662 /* Variable explains itself! */
1663 KdbpEvenThoughWeHaveABreakPointToReenableWeAlsoHaveARealSingleStep
= TRUE
;
1665 if ((KdbSingleStepOver
&& KdbpStepOverInstruction(KdbCurrentTrapFrame
->Tf
.Eip
)) ||
1666 (!KdbSingleStepOver
&& KdbpStepIntoInstruction(KdbCurrentTrapFrame
->Tf
.Eip
)))
1668 ASSERT((KdbCurrentTrapFrame
->Tf
.EFlags
& EFLAGS_TF
) == 0);
1669 /*KdbCurrentTrapFrame->Tf.EFlags &= ~EFLAGS_TF;*/
1673 Context
->EFlags
|= EFLAGS_TF
;
1677 /* We can't update the current thread's trapframe 'cause it might not have one */
1679 /* Detach from attached process */
1680 if (KdbCurrentProcess
!= KdbOriginalProcess
)
1682 KeUnstackDetachProcess(&KdbApcState
);
1685 /* Update the exception TrapFrame */
1686 KdbpKdbTrapFrameToTrapFrame(&KdbTrapFrame
, TrapFrame
);
1688 /* Decrement the entry count */
1689 InterlockedDecrement(&KdbEntryCount
);
1691 /* HACK: Raise back to old IRQL */
1692 KeRaiseIrql(OldIrql
, &OldIrql
);
1694 /* Leave critical section */
1695 __writeeflags(OldEflags
);
1697 /* Check if user requested a bugcheck */
1698 if (KdbpBugCheckRequested
)
1700 /* Clear the flag and bugcheck the system */
1701 KdbpBugCheckRequested
= FALSE
;
1702 KeBugCheck(MANUALLY_INITIATED_CRASH
);
1706 /* Clear debug status */
1707 if (ExceptionCode
== STATUS_BREAKPOINT
) /* FIXME: Why clear DR6 on INT3? */
1709 /* Set the RF flag so we don't trigger the same breakpoint again. */
1712 TrapFrame
->EFlags
|= EFLAGS_RF
;
1715 /* Clear dr6 status flags. */
1716 TrapFrame
->Dr6
&= ~0x0000e00f;
1718 if (!(KdbEnteredOnSingleStep
&& KdbSingleStepOver
))
1720 /* Skip the current instruction */
1725 return ContinueType
;
1731 KdbpGetCommandLineSettings(
1734 #define CONST_STR_LEN(x) (sizeof(x)/sizeof(x[0]) - 1)
1736 while (p1
&& (p1
= strchr(p1
, ' ')))
1738 /* Skip other spaces */
1739 while (*p1
== ' ') ++p1
;
1741 if (!_strnicmp(p1
, "KDSERIAL", CONST_STR_LEN("KDSERIAL")))
1743 p1
+= CONST_STR_LEN("KDSERIAL");
1744 KdbDebugState
|= KD_DEBUG_KDSERIAL
;
1745 KdpDebugMode
.Serial
= TRUE
;
1747 else if (!_strnicmp(p1
, "KDNOECHO", CONST_STR_LEN("KDNOECHO")))
1749 p1
+= CONST_STR_LEN("KDNOECHO");
1750 KdbDebugState
|= KD_DEBUG_KDNOECHO
;
1752 else if (!_strnicmp(p1
, "FIRSTCHANCE", CONST_STR_LEN("FIRSTCHANCE")))
1754 p1
+= CONST_STR_LEN("FIRSTCHANCE");
1755 KdbpSetEnterCondition(-1, TRUE
, KdbEnterAlways
);
1766 BOOLEAN Result
= TRUE
;
1774 Result
= KdpSafeReadMemory((ULONG_PTR
)Src
, Bytes
, Dest
);
1779 ULONG_PTR Start
, End
, Write
;
1781 for (Start
= (ULONG_PTR
)Src
,
1782 End
= Start
+ Bytes
,
1783 Write
= (ULONG_PTR
)Dest
;
1784 Result
&& (Start
< End
);
1786 if (!KdpSafeReadMemory(Start
, 1, (PVOID
)Write
))
1793 return Result
? STATUS_SUCCESS
: STATUS_ACCESS_VIOLATION
;
1797 KdbpSafeWriteMemory(
1802 BOOLEAN Result
= TRUE
;
1803 ULONG_PTR Start
, End
, Write
;
1805 for (Start
= (ULONG_PTR
)Src
,
1806 End
= Start
+ Bytes
,
1807 Write
= (ULONG_PTR
)Dest
;
1808 Result
&& (Start
< End
);
1810 if (!KdpSafeWriteMemory(Write
, 1, *((PCHAR
)Start
)))
1813 return Result
? STATUS_SUCCESS
: STATUS_ACCESS_VIOLATION
;