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 ******************************************************************/
14 #include <internal/debug.h>
16 /* TYPES *********************************************************************/
18 /* FIXME: NDK headers */
19 #define TempEsp TempEip
20 #define TempSegSs TempCs
22 /* DEFINES *******************************************************************/
24 #define KDB_STACK_SIZE (4096*3)
25 #define KDB_MAXIMUM_BREAKPOINT_COUNT 256
26 #define KDB_MAXIMUM_HW_BREAKPOINT_COUNT 4
27 #define KDB_MAXIMUM_SW_BREAKPOINT_COUNT 256
29 #define __STRING(x) #x
30 #define _STRING(x) __STRING(x)
32 /* GLOBALS *******************************************************************/
34 STATIC LONG KdbEntryCount
= 0;
35 STATIC CHAR KdbStack
[KDB_STACK_SIZE
];
37 STATIC ULONG KdbBreakPointCount
= 0; /* Number of used breakpoints in the array */
38 STATIC KDB_BREAKPOINT KdbBreakPoints
[KDB_MAXIMUM_BREAKPOINT_COUNT
] = {{0}}; /* Breakpoint array */
39 STATIC ULONG KdbSwBreakPointCount
= 0; /* Number of enabled software breakpoints */
40 STATIC ULONG KdbHwBreakPointCount
= 0; /* Number of enabled hardware breakpoints */
41 STATIC PKDB_BREAKPOINT KdbSwBreakPoints
[KDB_MAXIMUM_SW_BREAKPOINT_COUNT
]; /* Enabled software breakpoints, orderless */
42 STATIC PKDB_BREAKPOINT KdbHwBreakPoints
[KDB_MAXIMUM_HW_BREAKPOINT_COUNT
]; /* Enabled hardware breakpoints, orderless */
43 STATIC PKDB_BREAKPOINT KdbBreakPointToReenable
= NULL
; /* Set to a breakpoint struct when single stepping after
44 a software breakpoint was hit, to reenable it */
45 LONG KdbLastBreakPointNr
= -1; /* Index of the breakpoint which cause KDB to be entered */
46 ULONG KdbNumSingleSteps
= 0; /* How many single steps to do */
47 BOOLEAN KdbSingleStepOver
= FALSE
; /* Whether to step over calls/reps. */
48 ULONG KdbDebugState
= 0; /* KDBG Settings (NOECHO, KDSERIAL) */
49 STATIC BOOLEAN KdbEnteredOnSingleStep
= FALSE
; /* Set to true when KDB was entered because of single step */
50 PEPROCESS KdbCurrentProcess
= NULL
; /* The current process context in which KDB runs */
51 PEPROCESS KdbOriginalProcess
= NULL
; /* The process in whichs context KDB was intered */
52 PETHREAD KdbCurrentThread
= NULL
; /* The current thread context in which KDB runs */
53 PETHREAD KdbOriginalThread
= NULL
; /* The thread in whichs context KDB was entered */
54 PKDB_KTRAP_FRAME KdbCurrentTrapFrame
= NULL
; /* Pointer to the current trapframe */
55 STATIC KDB_KTRAP_FRAME KdbTrapFrame
= { { 0 } }; /* The trapframe which was passed to KdbEnterDebuggerException */
56 STATIC KDB_KTRAP_FRAME KdbThreadTrapFrame
= { { 0 } }; /* The trapframe of the current thread (KdbCurrentThread) */
57 STATIC KAPC_STATE KdbApcState
;
59 /* Array of conditions when to enter KDB */
60 STATIC KDB_ENTER_CONDITION KdbEnterConditions
[][2] =
62 /* First chance Last chance */
63 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* Zero devide */
64 { KdbEnterAlways
, KdbDoNotEnter
}, /* Debug trap */
65 { KdbDoNotEnter
, KdbEnterAlways
}, /* NMI */
66 { KdbEnterFromKmode
, KdbDoNotEnter
}, /* INT3 */
67 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* Overflow */
68 { KdbDoNotEnter
, KdbEnterFromKmode
},
69 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* Invalid opcode */
70 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* No math coprocessor fault */
71 { KdbEnterAlways
, KdbEnterAlways
},
72 { KdbEnterAlways
, KdbEnterAlways
},
73 { KdbDoNotEnter
, KdbEnterFromKmode
},
74 { KdbDoNotEnter
, KdbEnterFromKmode
},
75 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* Stack fault */
76 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* General protection fault */
77 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* Page fault */
78 { KdbEnterAlways
, KdbEnterAlways
}, /* Reserved (15) */
79 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* FPU fault */
80 { KdbDoNotEnter
, KdbEnterFromKmode
},
81 { KdbDoNotEnter
, KdbEnterFromKmode
},
82 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* SIMD fault */
83 { KdbDoNotEnter
, KdbEnterFromKmode
} /* Last entry: used for unknown exceptions */
86 /* Exception descriptions */
87 STATIC CONST PCHAR ExceptionNrToString
[] =
94 "BOUND range exceeded",
96 "No Math Coprocessor",
100 "Segment Not Present",
101 "Stack Segment Fault",
102 "General Protection",
111 /* FUNCTIONS *****************************************************************/
114 KdbpTrapFrameToKdbTrapFrame(PKTRAP_FRAME TrapFrame
, PKDB_KTRAP_FRAME KdbTrapFrame
)
116 /* Copy the TrapFrame only up to Eflags and zero the rest*/
117 RtlCopyMemory(&KdbTrapFrame
->Tf
, TrapFrame
, FIELD_OFFSET(KTRAP_FRAME
, Esp
));
118 RtlZeroMemory((PVOID
)((ULONG_PTR
)&KdbTrapFrame
->Tf
+ FIELD_OFFSET(KTRAP_FRAME
, Esp
)),
119 sizeof (KTRAP_FRAME
) - FIELD_OFFSET(KTRAP_FRAME
, Esp
));
121 "movl %%cr0, %0" "\n\t"
122 "movl %%cr2, %1" "\n\t"
123 "movl %%cr3, %2" "\n\t"
124 "movl %%cr4, %3" "\n\t"
125 : "=r"(KdbTrapFrame
->Cr0
), "=r"(KdbTrapFrame
->Cr2
),
126 "=r"(KdbTrapFrame
->Cr3
), "=r"(KdbTrapFrame
->Cr4
));
128 if (TrapFrame
->PreviousMode
== KernelMode
)
130 /* If the trapframe is a kmode one use the temp ss:esp */
131 KdbTrapFrame
->Tf
.Esp
= (ULONG
)TrapFrame
->TempEsp
;
132 KdbTrapFrame
->Tf
.Ss
= (USHORT
)((ULONG
)TrapFrame
->TempSegSs
& 0xFFFF);
136 /* Otherwise use ss:esp pushed by the CPU */
137 /* FIXME: maybe change all trapframes to always put ss:esp into tempss:tempesp so we
138 * can handle umode and kmode the same way */
139 KdbTrapFrame
->Tf
.Esp
= TrapFrame
->Esp
;
140 KdbTrapFrame
->Tf
.Ss
= TrapFrame
->Ss
;
143 /* FIXME: copy v86 registers if TrapFrame is a V86 trapframe */
147 KdbpKdbTrapFrameToTrapFrame(PKDB_KTRAP_FRAME KdbTrapFrame
, PKTRAP_FRAME TrapFrame
)
149 /* Copy the TrapFrame only up to Eflags and zero the rest*/
150 RtlCopyMemory(TrapFrame
, &KdbTrapFrame
->Tf
, FIELD_OFFSET(KTRAP_FRAME
, Esp
));
152 /* FIXME: write cr0, cr2, cr3 and cr4 (not needed atm) */
154 if (TrapFrame
->PreviousMode
== KernelMode
)
156 /* If the trapframe is a kmode one write to the temp ss:esp */
157 TrapFrame
->TempEsp
= (PVOID
)KdbTrapFrame
->Tf
.Esp
;
158 TrapFrame
->TempSegSs
= (PVOID
)(((ULONG
)TrapFrame
->TempSegSs
& ~0xffff) | KdbTrapFrame
->Tf
.Ss
);
162 /* Otherwise write to ss:esp pushed by the CPU */
163 /* FIXME: maybe change all trap-epilogs to always put temp ss:esp into ss:esp so we
164 * can handle umode and kmode the same way */
165 TrapFrame
->Esp
= KdbTrapFrame
->Tf
.Esp
;
166 TrapFrame
->Ss
= KdbTrapFrame
->Tf
.Ss
;
169 /* FIXME: copy v86 registers if TrapFrame is a V86 trapframe */
172 /*!\brief Overwrites the instruction at \a Address with \a NewInst and stores
173 * the old instruction in *OldInst.
175 * \param Process Process in which's context to overwrite the instruction.
176 * \param Address Address at which to overwrite the instruction.
177 * \param NewInst New instruction (written to \a Address)
178 * \param OldInst Old instruction (read from \a Address)
183 KdbpOverwriteInstruction(
184 IN PEPROCESS Process
,
185 IN ULONG_PTR Address
,
187 OUT PUCHAR OldInst OPTIONAL
)
191 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
194 /* Get the protection for the address. */
195 Protect
= MmGetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
));
197 /* Return if that page isn't present. */
198 if (Protect
& PAGE_NOACCESS
)
200 return STATUS_MEMORY_NOT_ALLOCATED
;
203 /* Attach to the process */
204 if (CurrentProcess
!= Process
)
206 KeStackAttachProcess(EPROCESS_TO_KPROCESS(Process
), &ApcState
);
209 /* Make the page writeable if it is read only. */
210 if (Protect
& (PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
))
212 MmSetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
),
213 (Protect
& ~(PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
)) | PAGE_READWRITE
);
216 /* Copy the old instruction back to the caller. */
219 Status
= KdbpSafeReadMemory(OldInst
, (PUCHAR
)Address
, 1);
220 if (!NT_SUCCESS(Status
))
222 if (Protect
& (PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
))
224 MmSetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
), Protect
);
226 /* Detach from process */
227 if (CurrentProcess
!= Process
)
235 /* Copy the new instruction in its place. */
236 Status
= KdbpSafeWriteMemory((PUCHAR
)Address
, &NewInst
, 1);
238 /* Restore the page protection. */
239 if (Protect
& (PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
))
241 MmSetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
), Protect
);
244 /* Detach from process */
245 if (CurrentProcess
!= Process
)
247 KeUnstackDetachProcess(&ApcState
);
253 /*!\brief Checks whether the given instruction can be single stepped or has to be
254 * stepped over using a temporary breakpoint.
256 * \retval TRUE Instruction is a call.
257 * \retval FALSE Instruction is not a call.
260 KdbpShouldStepOverInstruction(ULONG_PTR Eip
)
265 if (!NT_SUCCESS(KdbpSafeReadMemory(Mem
, (PVOID
)Eip
, sizeof (Mem
))))
267 KdbpPrint("Couldn't access memory at 0x%p\n", Eip
);
271 /* Check if the current instruction is a call. */
272 while ((i
< sizeof (Mem
)) && (Mem
[i
] == 0x66 || Mem
[i
] == 0x67))
274 if (i
== sizeof (Mem
))
276 if (Mem
[i
] == 0xE8 || Mem
[i
] == 0x9A || Mem
[i
] == 0xF2 || Mem
[i
] == 0xF3 ||
277 (((i
+ 1) < sizeof (Mem
)) && Mem
[i
] == 0xFF && (Mem
[i
+1] & 0x38) == 0x10))
284 /*!\brief Steps over an instruction
286 * If the given instruction should be stepped over, this function inserts a
287 * temporary breakpoint after the instruction and returns TRUE, otherwise it
290 * \retval TRUE Temporary breakpoint set after instruction.
291 * \retval FALSE No breakpoint was set.
294 KdbpStepOverInstruction(ULONG_PTR Eip
)
298 if (!KdbpShouldStepOverInstruction(Eip
))
301 InstLen
= KdbpGetInstLength(Eip
);
305 if (!NT_SUCCESS(KdbpInsertBreakPoint(Eip
+ InstLen
, KdbBreakPointTemporary
, 0, 0, NULL
, FALSE
, NULL
)))
311 /*!\brief Steps into an instruction (interrupts)
313 * If the given instruction should be stepped into, this function inserts a
314 * temporary breakpoint at the target instruction and returns TRUE, otherwise it
317 * \retval TRUE Temporary breakpoint set at target instruction.
318 * \retval FALSE No breakpoint was set.
321 KdbpStepIntoInstruction(ULONG_PTR Eip
)
330 if (!NT_SUCCESS(KdbpSafeReadMemory(Mem
, (PVOID
)Eip
, sizeof (Mem
))))
332 /*KdbpPrint("Couldn't access memory at 0x%p\n", Eip);*/
336 /* Check for INT instruction */
337 /* FIXME: Check for iret */
340 else if (Mem
[0] == 0xcd)
342 else if (Mem
[0] == 0xce && KdbCurrentTrapFrame
->Tf
.Eflags
& (1<<11)) /* 1 << 11 is the overflow flag */
347 if (IntVect
< 32) /* We should be informed about interrupts < 32 by the kernel, no need to breakpoint them */
352 /* Read the interrupt descriptor table register */
353 asm volatile("sidt %0" : : "m"(Idtr
.Limit
));
354 if (IntVect
>= (Idtr
.Limit
+ 1) / 8)
356 /*KdbpPrint("IDT does not contain interrupt vector %d\n.", IntVect);*/
360 /* Get the interrupt descriptor */
361 if (!NT_SUCCESS(KdbpSafeReadMemory(IntDesc
, (PVOID
)(Idtr
.Base
+ (IntVect
* 8)), sizeof (IntDesc
))))
363 /*KdbpPrint("Couldn't access memory at 0x%p\n", (ULONG_PTR)Idtr.Base + (IntVect * 8));*/
367 /* Check descriptor and get target eip (16 bit interrupt/trap gates not supported) */
368 if ((IntDesc
[1] & (1 << 15)) == 0) /* not present */
372 if ((IntDesc
[1] & 0x1f00) == 0x0500) /* Task gate */
374 /* FIXME: Task gates not supported */
377 else if (((IntDesc
[1] & 0x1fe0) == 0x0e00) || /* 32 bit Interrupt gate */
378 ((IntDesc
[1] & 0x1fe0) == 0x0f00)) /* 32 bit Trap gate */
380 /* FIXME: Should the segment selector of the interrupt gate be checked? */
381 TargetEip
= (IntDesc
[1] & 0xffff0000) | (IntDesc
[0] & 0x0000ffff);
388 /* Insert breakpoint */
389 if (!NT_SUCCESS(KdbpInsertBreakPoint(TargetEip
, KdbBreakPointTemporary
, 0, 0, NULL
, FALSE
, NULL
)))
395 /*!\brief Gets the number of the next breakpoint >= Start.
397 * \param Start Breakpoint number to start searching at. -1 if no more breakpoints are found.
399 * \returns Breakpoint number (-1 if no more breakpoints are found)
402 KdbpGetNextBreakPointNr(
403 IN ULONG Start OPTIONAL
)
405 for (; Start
< RTL_NUMBER_OF(KdbBreakPoints
); Start
++)
407 if (KdbBreakPoints
[Start
].Type
!= KdbBreakPointNone
)
413 /*!\brief Returns information of the specified breakpoint.
415 * \param BreakPointNr Number of the breakpoint to return information of.
416 * \param Address Receives the address of the breakpoint.
417 * \param Type Receives the type of the breakpoint (hardware or software)
418 * \param Size Size - for memory breakpoints.
419 * \param AccessType Access type - for hardware breakpoints.
420 * \param DebugReg Debug register - for enabled hardware breakpoints.
421 * \param Enabled Whether the breakpoint is enabled or not.
422 * \param Process The owning process of the breakpoint.
423 * \param ConditionExpression The expression which was given as condition for the bp.
425 * \returns NULL on failure, pointer to a KDB_BREAKPOINT struct on success.
428 KdbpGetBreakPointInfo(
429 IN ULONG BreakPointNr
,
430 OUT ULONG_PTR
*Address OPTIONAL
,
431 OUT KDB_BREAKPOINT_TYPE
*Type OPTIONAL
,
432 OUT UCHAR
*Size OPTIONAL
,
433 OUT KDB_ACCESS_TYPE
*AccessType OPTIONAL
,
434 OUT UCHAR
*DebugReg OPTIONAL
,
435 OUT BOOLEAN
*Enabled OPTIONAL
,
436 OUT BOOLEAN
*Global OPTIONAL
,
437 OUT PEPROCESS
*Process OPTIONAL
,
438 OUT PCHAR
*ConditionExpression OPTIONAL
)
442 if (BreakPointNr
>= RTL_NUMBER_OF(KdbBreakPoints
) ||
443 KdbBreakPoints
[BreakPointNr
].Type
== KdbBreakPointNone
)
448 bp
= KdbBreakPoints
+ BreakPointNr
;
450 *Address
= bp
->Address
;
453 if (bp
->Type
== KdbBreakPointHardware
)
456 *Size
= bp
->Data
.Hw
.Size
;
457 if (AccessType
!= NULL
)
458 *AccessType
= bp
->Data
.Hw
.AccessType
;
459 if (DebugReg
!= NULL
&& bp
->Enabled
)
460 *DebugReg
= bp
->Data
.Hw
.DebugReg
;
463 *Enabled
= bp
->Enabled
;
465 *Global
= bp
->Global
;
467 *Process
= bp
->Process
;
468 if (ConditionExpression
!= NULL
)
469 *ConditionExpression
= bp
->ConditionExpression
;
474 /*!\brief Inserts a breakpoint into the breakpoint array.
476 * The \a Process of the breakpoint is set to \a KdbCurrentProcess
478 * \param Address Address at which to set the breakpoint.
479 * \param Type Type of breakpoint (hardware or software)
480 * \param Size Size of breakpoint (for hardware/memory breakpoints)
481 * \param AccessType Access type (for hardware breakpoins)
482 * \param ConditionExpression Expression which must evaluate to true for conditional breakpoints.
483 * \param Global Wether the breakpoint is global or local to a process.
484 * \param BreakPointNumber Receives the breakpoint number on success
489 KdbpInsertBreakPoint(
490 IN ULONG_PTR Address
,
491 IN KDB_BREAKPOINT_TYPE Type
,
492 IN UCHAR Size OPTIONAL
,
493 IN KDB_ACCESS_TYPE AccessType OPTIONAL
,
494 IN PCHAR ConditionExpression OPTIONAL
,
496 OUT PULONG BreakPointNumber OPTIONAL
)
500 PCHAR ConditionExpressionDup
;
504 ASSERT(Type
!= KdbBreakPointNone
);
506 if (Type
== KdbBreakPointHardware
)
508 if ((Address
% Size
) != 0)
510 KdbpPrint("Address (0x%p) must be aligned to a multiple of the size (%d)\n", Address
, Size
);
511 return STATUS_UNSUCCESSFUL
;
513 if (AccessType
== KdbAccessExec
&& Size
!= 1)
515 KdbpPrint("Size must be 1 for execution breakpoints.\n");
516 return STATUS_UNSUCCESSFUL
;
520 if (KdbBreakPointCount
== KDB_MAXIMUM_BREAKPOINT_COUNT
)
522 return STATUS_UNSUCCESSFUL
;
525 /* Parse conditon expression string and duplicate it */
526 if (ConditionExpression
!= NULL
)
528 Condition
= KdbpRpnParseExpression(ConditionExpression
, &ErrOffset
, ErrMsg
);
529 if (Condition
== NULL
)
532 KdbpPrint("Couldn't parse expression: %s at character %d\n", ErrMsg
, ErrOffset
);
534 KdbpPrint("Couldn't parse expression: %s", ErrMsg
);
535 return STATUS_UNSUCCESSFUL
;
538 i
= strlen(ConditionExpression
) + 1;
539 ConditionExpressionDup
= ExAllocatePoolWithTag(NonPagedPool
, i
, TAG_KDBG
);
540 RtlCopyMemory(ConditionExpressionDup
, ConditionExpression
, i
);
546 ConditionExpressionDup
= NULL
;
549 /* Find unused breakpoint */
550 if (Type
== KdbBreakPointTemporary
)
552 for (i
= RTL_NUMBER_OF(KdbBreakPoints
) - 1; i
>= 0; i
--)
554 if (KdbBreakPoints
[i
].Type
== KdbBreakPointNone
)
560 for (i
= 0; i
< (LONG
)RTL_NUMBER_OF(KdbBreakPoints
); i
++)
562 if (KdbBreakPoints
[i
].Type
== KdbBreakPointNone
)
566 ASSERT(i
< (LONG
)RTL_NUMBER_OF(KdbBreakPoints
));
568 /* Set the breakpoint */
569 ASSERT(KdbCurrentProcess
!= NULL
);
570 KdbBreakPoints
[i
].Type
= Type
;
571 KdbBreakPoints
[i
].Address
= Address
;
572 KdbBreakPoints
[i
].Enabled
= FALSE
;
573 KdbBreakPoints
[i
].Global
= Global
;
574 KdbBreakPoints
[i
].Process
= KdbCurrentProcess
;
575 KdbBreakPoints
[i
].ConditionExpression
= ConditionExpressionDup
;
576 KdbBreakPoints
[i
].Condition
= Condition
;
577 if (Type
== KdbBreakPointHardware
)
580 KdbBreakPoints
[i
].Data
.Hw
.Size
= Size
;
581 KdbBreakPoints
[i
].Data
.Hw
.AccessType
= AccessType
;
583 KdbBreakPointCount
++;
585 if (Type
!= KdbBreakPointTemporary
)
586 KdbpPrint("Breakpoint %d inserted.\n", i
);
588 /* Try to enable the breakpoint */
589 KdbpEnableBreakPoint(i
, NULL
);
591 /* Return the breakpoint number */
592 if (BreakPointNumber
!= NULL
)
593 *BreakPointNumber
= i
;
595 return STATUS_SUCCESS
;
598 /*!\brief Deletes a breakpoint
600 * \param BreakPointNr Number of the breakpoint to delete. Can be -1
601 * \param BreakPoint Breakpoint to delete. Can be NULL.
603 * \retval TRUE Success.
604 * \retval FALSE Failure (invalid breakpoint number)
607 KdbpDeleteBreakPoint(
608 IN LONG BreakPointNr OPTIONAL
,
609 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL
)
611 if (BreakPointNr
< 0)
613 ASSERT(BreakPoint
!= NULL
);
614 BreakPointNr
= BreakPoint
- KdbBreakPoints
;
616 if (BreakPointNr
< 0 || BreakPointNr
>= KDB_MAXIMUM_BREAKPOINT_COUNT
)
618 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
621 if (BreakPoint
== NULL
)
623 BreakPoint
= KdbBreakPoints
+ BreakPointNr
;
625 if (BreakPoint
->Type
== KdbBreakPointNone
)
627 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
631 if (BreakPoint
->Enabled
&&
632 !KdbpDisableBreakPoint(-1, BreakPoint
))
635 if (BreakPoint
->Type
!= KdbBreakPointTemporary
)
636 KdbpPrint("Breakpoint %d deleted.\n", BreakPointNr
);
637 BreakPoint
->Type
= KdbBreakPointNone
;
638 KdbBreakPointCount
--;
643 /*!\brief Checks if the breakpoint was set by the debugger
645 * Tries to find a breakpoint in the breakpoint array which caused
646 * the debug exception to happen.
648 * \param ExpNr Exception Number (1 or 3)
649 * \param TrapFrame Exception trapframe
651 * \returns Breakpoint number, -1 on error.
654 KdbpIsBreakPointOurs(
656 IN PKTRAP_FRAME TrapFrame
)
659 ASSERT(ExpNr
== 1 || ExpNr
== 3);
661 if (ExpNr
== 3) /* Software interrupt */
663 ULONG_PTR BpEip
= (ULONG_PTR
)TrapFrame
->Eip
- 1; /* Get EIP of INT3 instruction */
664 for (i
= 0; i
< KdbSwBreakPointCount
; i
++)
666 ASSERT((KdbSwBreakPoints
[i
]->Type
== KdbBreakPointSoftware
||
667 KdbSwBreakPoints
[i
]->Type
== KdbBreakPointTemporary
));
668 ASSERT(KdbSwBreakPoints
[i
]->Enabled
);
669 if (KdbSwBreakPoints
[i
]->Address
== BpEip
)
671 return KdbSwBreakPoints
[i
] - KdbBreakPoints
;
675 else if (ExpNr
== 1) /* Hardware interrupt */
678 for (i
= 0; i
< KdbHwBreakPointCount
; i
++)
680 ASSERT(KdbHwBreakPoints
[i
]->Type
== KdbBreakPointHardware
&&
681 KdbHwBreakPoints
[i
]->Enabled
);
682 DebugReg
= KdbHwBreakPoints
[i
]->Data
.Hw
.DebugReg
;
683 if ((TrapFrame
->Dr6
& (1 << DebugReg
)) != 0)
685 return KdbHwBreakPoints
[i
] - KdbBreakPoints
;
693 /*!\brief Enables a breakpoint.
695 * \param BreakPointNr Number of the breakpoint to enable Can be -1.
696 * \param BreakPoint Breakpoint to enable. Can be NULL.
698 * \retval TRUE Success.
699 * \retval FALSE Failure.
701 * \sa KdbpDisableBreakPoint
704 KdbpEnableBreakPoint(
705 IN LONG BreakPointNr OPTIONAL
,
706 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL
)
712 if (BreakPointNr
< 0)
714 ASSERT(BreakPoint
!= NULL
);
715 BreakPointNr
= BreakPoint
- KdbBreakPoints
;
717 if (BreakPointNr
< 0 || BreakPointNr
>= KDB_MAXIMUM_BREAKPOINT_COUNT
)
719 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
722 if (BreakPoint
== NULL
)
724 BreakPoint
= KdbBreakPoints
+ BreakPointNr
;
726 if (BreakPoint
->Type
== KdbBreakPointNone
)
728 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
732 if (BreakPoint
->Enabled
== TRUE
)
734 KdbpPrint("Breakpoint %d is already enabled.\n", BreakPointNr
);
738 if (BreakPoint
->Type
== KdbBreakPointSoftware
||
739 BreakPoint
->Type
== KdbBreakPointTemporary
)
741 if (KdbSwBreakPointCount
>= KDB_MAXIMUM_SW_BREAKPOINT_COUNT
)
743 KdbpPrint("Maximum number of SW breakpoints (%d) used. "
744 "Disable another breakpoint in order to enable this one.\n",
745 KDB_MAXIMUM_SW_BREAKPOINT_COUNT
);
748 Status
= KdbpOverwriteInstruction(BreakPoint
->Process
, BreakPoint
->Address
,
749 0xCC, &BreakPoint
->Data
.SavedInstruction
);
750 if (!NT_SUCCESS(Status
))
752 KdbpPrint("Couldn't access memory at 0x%p\n", BreakPoint
->Address
);
755 KdbSwBreakPoints
[KdbSwBreakPointCount
++] = BreakPoint
;
759 if (BreakPoint
->Data
.Hw
.AccessType
== KdbAccessExec
)
760 ASSERT(BreakPoint
->Data
.Hw
.Size
== 1);
761 ASSERT((BreakPoint
->Address
% BreakPoint
->Data
.Hw
.Size
) == 0);
762 if (KdbHwBreakPointCount
>= KDB_MAXIMUM_HW_BREAKPOINT_COUNT
)
764 KdbpPrint("Maximum number of HW breakpoints (%d) already used. "
765 "Disable another breakpoint in order to enable this one.\n",
766 KDB_MAXIMUM_HW_BREAKPOINT_COUNT
);
770 /* Find unused hw breakpoint */
771 ASSERT(KDB_MAXIMUM_HW_BREAKPOINT_COUNT
== 4);
772 for (i
= 0; i
< KDB_MAXIMUM_HW_BREAKPOINT_COUNT
; i
++)
774 if ((KdbTrapFrame
.Tf
.Dr7
& (0x3 << (i
* 2))) == 0)
777 ASSERT(i
< KDB_MAXIMUM_HW_BREAKPOINT_COUNT
);
779 /* Set the breakpoint address. */
783 KdbTrapFrame
.Tf
.Dr0
= BreakPoint
->Address
;
786 KdbTrapFrame
.Tf
.Dr1
= BreakPoint
->Address
;
789 KdbTrapFrame
.Tf
.Dr2
= BreakPoint
->Address
;
792 KdbTrapFrame
.Tf
.Dr3
= BreakPoint
->Address
;
796 /* Enable the global breakpoint */
797 KdbTrapFrame
.Tf
.Dr7
|= (0x2 << (i
* 2));
799 /* Enable the exact match bits. */
800 KdbTrapFrame
.Tf
.Dr7
|= 0x00000300;
802 /* Clear existing state. */
803 KdbTrapFrame
.Tf
.Dr7
&= ~(0xF << (16 + (i
* 4)));
805 /* Set the breakpoint type. */
806 switch (BreakPoint
->Data
.Hw
.AccessType
)
815 case KdbAccessReadWrite
:
823 KdbTrapFrame
.Tf
.Dr7
|= (ul
<< (16 + (i
* 4)));
825 /* Set the breakpoint length. */
826 KdbTrapFrame
.Tf
.Dr7
|= ((BreakPoint
->Data
.Hw
.Size
- 1) << (18 + (i
* 4)));
828 /* Update KdbCurrentTrapFrame - values are taken from there by the CLI */
829 if (&KdbTrapFrame
!= KdbCurrentTrapFrame
)
831 KdbCurrentTrapFrame
->Tf
.Dr0
= KdbTrapFrame
.Tf
.Dr0
;
832 KdbCurrentTrapFrame
->Tf
.Dr1
= KdbTrapFrame
.Tf
.Dr1
;
833 KdbCurrentTrapFrame
->Tf
.Dr2
= KdbTrapFrame
.Tf
.Dr2
;
834 KdbCurrentTrapFrame
->Tf
.Dr3
= KdbTrapFrame
.Tf
.Dr3
;
835 KdbCurrentTrapFrame
->Tf
.Dr6
= KdbTrapFrame
.Tf
.Dr6
;
836 KdbCurrentTrapFrame
->Tf
.Dr7
= KdbTrapFrame
.Tf
.Dr7
;
839 BreakPoint
->Data
.Hw
.DebugReg
= i
;
840 KdbHwBreakPoints
[KdbHwBreakPointCount
++] = BreakPoint
;
843 BreakPoint
->Enabled
= TRUE
;
844 if (BreakPoint
->Type
!= KdbBreakPointTemporary
)
845 KdbpPrint("Breakpoint %d enabled.\n", BreakPointNr
);
849 /*!\brief Disables a breakpoint.
851 * \param BreakPointNr Number of the breakpoint to disable. Can be -1
852 * \param BreakPoint Breakpoint to disable. Can be NULL.
854 * \retval TRUE Success.
855 * \retval FALSE Failure.
857 * \sa KdbpEnableBreakPoint
860 KdbpDisableBreakPoint(
861 IN LONG BreakPointNr OPTIONAL
,
862 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL
)
867 if (BreakPointNr
< 0)
869 ASSERT(BreakPoint
!= NULL
);
870 BreakPointNr
= BreakPoint
- KdbBreakPoints
;
872 if (BreakPointNr
< 0 || BreakPointNr
>= KDB_MAXIMUM_BREAKPOINT_COUNT
)
874 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
877 if (BreakPoint
== NULL
)
879 BreakPoint
= KdbBreakPoints
+ BreakPointNr
;
881 if (BreakPoint
->Type
== KdbBreakPointNone
)
883 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
887 if (BreakPoint
->Enabled
== FALSE
)
889 KdbpPrint("Breakpoint %d is not enabled.\n", BreakPointNr
);
893 if (BreakPoint
->Type
== KdbBreakPointSoftware
||
894 BreakPoint
->Type
== KdbBreakPointTemporary
)
896 ASSERT(KdbSwBreakPointCount
> 0);
897 Status
= KdbpOverwriteInstruction(BreakPoint
->Process
, BreakPoint
->Address
,
898 BreakPoint
->Data
.SavedInstruction
, NULL
);
899 if (!NT_SUCCESS(Status
))
901 KdbpPrint("Couldn't restore original instruction.\n");
905 for (i
= 0; i
< KdbSwBreakPointCount
; i
++)
907 if (KdbSwBreakPoints
[i
] == BreakPoint
)
909 KdbSwBreakPoints
[i
] = KdbSwBreakPoints
[--KdbSwBreakPointCount
];
910 i
= -1; /* if the last breakpoint is disabled dont break with i >= KdbSwBreakPointCount */
914 if (i
!= (UINT
)-1) /* not found */
919 ASSERT(BreakPoint
->Type
== KdbBreakPointHardware
);
921 /* Clear the breakpoint. */
922 KdbTrapFrame
.Tf
.Dr7
&= ~(0x3 << (BreakPoint
->Data
.Hw
.DebugReg
* 2));
923 if ((KdbTrapFrame
.Tf
.Dr7
& 0xFF) == 0)
926 * If no breakpoints are enabled then clear the exact match flags.
928 KdbTrapFrame
.Tf
.Dr7
&= 0xFFFFFCFF;
931 for (i
= 0; i
< KdbHwBreakPointCount
; i
++)
933 if (KdbHwBreakPoints
[i
] == BreakPoint
)
935 KdbHwBreakPoints
[i
] = KdbHwBreakPoints
[--KdbHwBreakPointCount
];
936 i
= -1; /* if the last breakpoint is disabled dont break with i >= KdbHwBreakPointCount */
940 if (i
!= (UINT
)-1) /* not found */
944 BreakPoint
->Enabled
= FALSE
;
945 if (BreakPoint
->Type
!= KdbBreakPointTemporary
)
946 KdbpPrint("Breakpoint %d disabled.\n", BreakPointNr
);
950 /*!\brief Gets the first or last chance enter-condition for exception nr. \a ExceptionNr
952 * \param ExceptionNr Number of the exception to get condition of.
953 * \param FirstChance Whether to get first or last chance condition.
954 * \param Condition Receives the condition setting.
956 * \retval TRUE Success.
957 * \retval FALSE Failure (invalid exception nr)
960 KdbpGetEnterCondition(
962 IN BOOLEAN FirstChance
,
963 OUT KDB_ENTER_CONDITION
*Condition
)
965 if (ExceptionNr
>= (LONG
)RTL_NUMBER_OF(KdbEnterConditions
))
968 *Condition
= KdbEnterConditions
[ExceptionNr
][FirstChance
? 0 : 1];
972 /*!\brief Sets the first or last chance enter-condition for exception nr. \a ExceptionNr
974 * \param ExceptionNr Number of the exception to set condition of (-1 for all)
975 * \param FirstChance Whether to set first or last chance condition.
976 * \param Condition The new condition setting.
978 * \retval TRUE Success.
979 * \retval FALSE Failure (invalid exception nr)
982 KdbpSetEnterCondition(
984 IN BOOLEAN FirstChance
,
985 IN KDB_ENTER_CONDITION Condition
)
989 for (ExceptionNr
= 0; ExceptionNr
< (LONG
)RTL_NUMBER_OF(KdbEnterConditions
); ExceptionNr
++)
991 if (ExceptionNr
== 1 || ExceptionNr
== 8 ||
992 ExceptionNr
== 9 || ExceptionNr
== 15) /* Reserved exceptions */
996 KdbEnterConditions
[ExceptionNr
][FirstChance
? 0 : 1] = Condition
;
1001 if (ExceptionNr
>= (LONG
)RTL_NUMBER_OF(KdbEnterConditions
) ||
1002 ExceptionNr
== 1 || ExceptionNr
== 8 || /* Do not allow changing of the debug */
1003 ExceptionNr
== 9 || ExceptionNr
== 15) /* trap or reserved exceptions */
1007 KdbEnterConditions
[ExceptionNr
][FirstChance
? 0 : 1] = Condition
;
1012 /*!\brief Switches to another thread context
1014 * \param ThreadId Id of the thread to switch to.
1016 * \retval TRUE Success.
1017 * \retval FALSE Failure (i.e. invalid thread id)
1023 PETHREAD Thread
= NULL
;
1026 /* Get a pointer to the thread */
1027 if (!NT_SUCCESS(PsLookupThreadByThreadId(ThreadId
, &Thread
)))
1029 KdbpPrint("Invalid thread id: 0x%08x\n", (UINT
)ThreadId
);
1032 Process
= Thread
->ThreadsProcess
;
1034 if (KeIsExecutingDpc() && Process
!= KdbCurrentProcess
)
1036 KdbpPrint("Cannot attach to thread within another process while executing a DPC.\n");
1040 /* Save the current thread's context (if we previously attached to a thread) */
1041 if (KdbCurrentThread
!= KdbOriginalThread
)
1043 ASSERT(KdbCurrentTrapFrame
== &KdbThreadTrapFrame
);
1044 KdbpKdbTrapFrameToTrapFrame(KdbCurrentTrapFrame
, KdbCurrentThread
->Tcb
.TrapFrame
);
1048 ASSERT(KdbCurrentTrapFrame
== &KdbTrapFrame
);
1051 /* Switch to the thread's context */
1052 if (Thread
!= KdbOriginalThread
)
1054 if (Thread
->Tcb
.TrapFrame
== NULL
)
1056 KdbpPrint("Threads TrapFrame is NULL! Cannot attach.\n");
1059 KdbpTrapFrameToKdbTrapFrame(Thread
->Tcb
.TrapFrame
, &KdbThreadTrapFrame
);
1060 KdbCurrentTrapFrame
= &KdbThreadTrapFrame
;
1062 else /* Switching back to original thread */
1064 KdbCurrentTrapFrame
= &KdbTrapFrame
;
1066 KdbCurrentThread
= Thread
;
1068 /* Attach to the thread's process */
1069 ASSERT(KdbCurrentProcess
== PsGetCurrentProcess());
1070 if (KdbCurrentProcess
!= Process
)
1072 if (KdbCurrentProcess
!= KdbOriginalProcess
) /* detach from previously attached process */
1074 KeUnstackDetachProcess(&KdbApcState
);
1076 if (KdbOriginalProcess
!= Process
)
1078 KeStackAttachProcess(EPROCESS_TO_KPROCESS(Process
), &KdbApcState
);
1080 KdbCurrentProcess
= Process
;
1086 /*!\brief Switches to another process/thread context
1088 * This function switches to the first thread in the specified process.
1090 * \param ProcessId Id of the process to switch to.
1092 * \retval TRUE Success.
1093 * \retval FALSE Failure (i.e. invalid process id)
1096 KdbpAttachToProcess(
1099 PEPROCESS Process
= NULL
;
1103 /* Get a pointer to the process */
1104 if (!NT_SUCCESS(PsLookupProcessByProcessId(ProcessId
, &Process
)))
1106 KdbpPrint("Invalid process id: 0x%08x\n", (UINT
)ProcessId
);
1110 Entry
= Process
->ThreadListHead
.Flink
;
1111 if (Entry
== &KdbCurrentProcess
->ThreadListHead
)
1113 KdbpPrint("No threads in process 0x%08x, cannot attach to process!\n", (UINT
)ProcessId
);
1117 Thread
= CONTAINING_RECORD(Entry
, ETHREAD
, ThreadListEntry
);
1119 return KdbpAttachToThread(Thread
->Cid
.UniqueThread
);
1122 /*!\brief Calls the main loop ...
1127 KdbpCliMainLoop(KdbEnteredOnSingleStep
);
1130 /*!\brief Internal function to enter KDB.
1132 * Disables interrupts, releases display ownership, ...
1138 PVOID SavedInitialStack
, SavedStackBase
, SavedKernelStack
;
1139 ULONG SavedStackLimit
;
1142 if (KdpDebugMode
.Screen
)
1144 HalReleaseDisplayOwnership();
1147 /* Call the interface's main loop on a different stack */
1148 Thread
= PsGetCurrentThread();
1149 SavedInitialStack
= Thread
->Tcb
.InitialStack
;
1150 SavedStackBase
= Thread
->Tcb
.StackBase
;
1151 SavedStackLimit
= Thread
->Tcb
.StackLimit
;
1152 SavedKernelStack
= Thread
->Tcb
.KernelStack
;
1153 Thread
->Tcb
.InitialStack
= Thread
->Tcb
.StackBase
= (char*)KdbStack
+ KDB_STACK_SIZE
;
1154 Thread
->Tcb
.StackLimit
= (ULONG
)KdbStack
;
1155 Thread
->Tcb
.KernelStack
= (char*)KdbStack
+ KDB_STACK_SIZE
;
1157 /*KdbpPrint("Switching to KDB stack 0x%08x-0x%08x\n", Thread->Tcb.StackLimit, Thread->Tcb.StackBase);*/
1159 KdbpStackSwitchAndCall(Thread
->Tcb
.KernelStack
, KdbpCallMainLoop
);
1161 Thread
->Tcb
.InitialStack
= SavedInitialStack
;
1162 Thread
->Tcb
.StackBase
= SavedStackBase
;
1163 Thread
->Tcb
.StackLimit
= SavedStackLimit
;
1164 Thread
->Tcb
.KernelStack
= SavedKernelStack
;
1168 /*!\brief KDB Exception filter
1170 * Called by the exception dispatcher.
1172 * \param ExceptionRecord Unused.
1173 * \param PreviousMode UserMode if the exception was raised from umode, otherwise KernelMode.
1174 * \param Context Unused.
1175 * \param TrapFrame Exception TrapFrame.
1176 * \param FirstChance TRUE when called before exception frames were serached,
1177 * FALSE for the second call.
1179 * \returns KD_CONTINUE_TYPE
1182 KdbEnterDebuggerException(
1183 IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL
,
1184 IN KPROCESSOR_MODE PreviousMode
,
1185 IN PCONTEXT Context OPTIONAL
,
1186 IN OUT PKTRAP_FRAME TrapFrame
,
1187 IN BOOLEAN FirstChance
)
1189 ULONG ExpNr
= (ULONG
)TrapFrame
->DebugArgMark
;
1190 KDB_ENTER_CONDITION EnterCondition
;
1191 KD_CONTINUE_TYPE ContinueType
= kdHandleException
;
1192 PKDB_BREAKPOINT BreakPoint
;
1195 BOOLEAN Resume
= FALSE
;
1196 BOOLEAN EnterConditionMet
= TRUE
;
1199 KdbCurrentProcess
= PsGetCurrentProcess();
1201 /* Set continue type to kdContinue for single steps and breakpoints */
1202 if (ExpNr
== 1 || ExpNr
== 3)
1203 ContinueType
= kdContinue
;
1205 /* Check if we should handle the exception. */
1206 ul
= min(ExpNr
, RTL_NUMBER_OF(KdbEnterConditions
) - 1);
1207 EnterCondition
= KdbEnterConditions
[ul
][FirstChance
? 0 : 1];
1208 if (EnterCondition
== KdbDoNotEnter
||
1209 (EnterCondition
== KdbEnterFromUmode
&& PreviousMode
!= UserMode
) ||
1210 (EnterCondition
== KdbEnterFromKmode
&& PreviousMode
!= KernelMode
))
1212 EnterConditionMet
= FALSE
;
1215 /* If we stopped on one of our breakpoints then let the user know. */
1216 KdbLastBreakPointNr
= -1;
1217 KdbEnteredOnSingleStep
= FALSE
;
1219 if (FirstChance
&& (ExpNr
== 1 || ExpNr
== 3) &&
1220 (KdbLastBreakPointNr
= KdbpIsBreakPointOurs(ExpNr
, TrapFrame
)) >= 0)
1222 BreakPoint
= KdbBreakPoints
+ KdbLastBreakPointNr
;
1227 * The breakpoint will point to the next instruction by default so
1228 * point it back to the start of original instruction.
1233 * ... and restore the original instruction.
1235 if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess
, BreakPoint
->Address
,
1236 BreakPoint
->Data
.SavedInstruction
, NULL
)))
1238 DbgPrint("Couldn't restore original instruction after INT3! Cannot continue execution.\n");
1243 if ((BreakPoint
->Type
== KdbBreakPointHardware
) &&
1244 (BreakPoint
->Data
.Hw
.AccessType
== KdbAccessExec
))
1246 Resume
= TRUE
; /* Set the resume flag when continuing execution */
1250 * When a temporary breakpoint is hit we have to make sure that we are
1251 * in the same context in which it was set, otherwise it could happen
1252 * that another process/thread hits it before and it gets deleted.
1254 else if (BreakPoint
->Type
== KdbBreakPointTemporary
&&
1255 BreakPoint
->Process
== KdbCurrentProcess
)
1257 ASSERT((TrapFrame
->Eflags
& X86_EFLAGS_TF
) == 0);
1260 * Delete the temporary breakpoint which was used to step over or into the instruction.
1262 KdbpDeleteBreakPoint(-1, BreakPoint
);
1264 if (--KdbNumSingleSteps
> 0)
1266 if ((KdbSingleStepOver
&& !KdbpStepOverInstruction(TrapFrame
->Eip
)) ||
1267 (!KdbSingleStepOver
&& !KdbpStepIntoInstruction(TrapFrame
->Eip
)))
1269 TrapFrame
->Eflags
|= X86_EFLAGS_TF
;
1271 goto continue_execution
; /* return */
1274 KdbEnteredOnSingleStep
= TRUE
;
1278 * If we hit a breakpoint set by the debugger we set the single step flag,
1279 * ignore the next single step and reenable the breakpoint.
1281 else if (BreakPoint
->Type
== KdbBreakPointSoftware
||
1282 BreakPoint
->Type
== KdbBreakPointTemporary
)
1285 TrapFrame
->Eflags
|= X86_EFLAGS_TF
;
1286 KdbBreakPointToReenable
= BreakPoint
;
1290 * Make sure that the breakpoint should be triggered in this context
1292 if (!BreakPoint
->Global
&& BreakPoint
->Process
!= KdbCurrentProcess
)
1294 goto continue_execution
; /* return */
1298 * Check if the condition for the breakpoint is met.
1300 if (BreakPoint
->Condition
!= NULL
)
1302 /* Setup the KDB trap frame */
1303 KdbpTrapFrameToKdbTrapFrame(TrapFrame
, &KdbTrapFrame
);
1306 if (!KdbpRpnEvaluateParsedExpression(BreakPoint
->Condition
, &KdbTrapFrame
, &ull
, NULL
, NULL
))
1308 /* FIXME: Print warning? */
1310 else if (ull
== 0) /* condition is not met */
1312 goto continue_execution
; /* return */
1316 if (BreakPoint
->Type
== KdbBreakPointSoftware
)
1318 DbgPrint("Entered debugger on breakpoint #%d: EXEC 0x%04x:0x%08x\n",
1319 KdbLastBreakPointNr
, TrapFrame
->Cs
& 0xffff, TrapFrame
->Eip
);
1321 else if (BreakPoint
->Type
== KdbBreakPointHardware
)
1323 DbgPrint("Entered debugger on breakpoint #%d: %s 0x%08x\n",
1324 KdbLastBreakPointNr
,
1325 (BreakPoint
->Data
.Hw
.AccessType
== KdbAccessRead
) ? "READ" :
1326 ((BreakPoint
->Data
.Hw
.AccessType
== KdbAccessWrite
) ? "WRITE" :
1327 ((BreakPoint
->Data
.Hw
.AccessType
== KdbAccessReadWrite
) ? "RDWR" : "EXEC")
1334 else if (ExpNr
== 1)
1336 /* Silently ignore a debugger initiated single step. */
1337 if ((TrapFrame
->Dr6
& 0xf) == 0 && KdbBreakPointToReenable
!= NULL
)
1339 /* FIXME: Make sure that the breakpoint was really hit (check bp->Address vs. tf->Eip) */
1340 BreakPoint
= KdbBreakPointToReenable
;
1341 KdbBreakPointToReenable
= NULL
;
1342 ASSERT(BreakPoint
->Type
== KdbBreakPointSoftware
||
1343 BreakPoint
->Type
== KdbBreakPointTemporary
);
1346 * Reenable the breakpoint we disabled to execute the breakpointed
1349 if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess
, BreakPoint
->Address
, 0xCC,
1350 &BreakPoint
->Data
.SavedInstruction
)))
1352 DbgPrint("Warning: Couldn't reenable breakpoint %d\n",
1353 BreakPoint
- KdbBreakPoints
);
1356 /* Unset TF if we are no longer single stepping. */
1357 if (KdbNumSingleSteps
== 0)
1358 TrapFrame
->Eflags
&= ~X86_EFLAGS_TF
;
1359 goto continue_execution
; /* return */
1362 /* Check if we expect a single step */
1363 if ((TrapFrame
->Dr6
& 0xf) == 0 && KdbNumSingleSteps
> 0)
1365 /*ASSERT((TrapFrame->Eflags & X86_EFLAGS_TF) != 0);*/
1366 if (--KdbNumSingleSteps
> 0)
1368 if ((KdbSingleStepOver
&& KdbpStepOverInstruction(TrapFrame
->Eip
)) ||
1369 (!KdbSingleStepOver
&& KdbpStepIntoInstruction(TrapFrame
->Eip
)))
1371 TrapFrame
->Eflags
&= ~X86_EFLAGS_TF
;
1375 TrapFrame
->Eflags
|= X86_EFLAGS_TF
;
1377 goto continue_execution
; /* return */
1380 TrapFrame
->Eflags
&= ~X86_EFLAGS_TF
;
1381 KdbEnteredOnSingleStep
= TRUE
;
1385 if (!EnterConditionMet
)
1387 return ContinueType
;
1389 DbgPrint("Entered debugger on unexpected debug trap!\n");
1392 else if (ExpNr
== 3)
1394 if (KdbInitFileBuffer
!= NULL
)
1396 KdbpCliInterpretInitFile();
1397 EnterConditionMet
= FALSE
;
1399 if (!EnterConditionMet
)
1401 return ContinueType
;
1404 DbgPrint("Entered debugger on embedded INT3 at 0x%04x:0x%08x.\n",
1405 TrapFrame
->Cs
& 0xffff, TrapFrame
->Eip
- 1);
1409 CONST PCHAR ExceptionString
= (ExpNr
< RTL_NUMBER_OF(ExceptionNrToString
)) ?
1410 (ExceptionNrToString
[ExpNr
]) :
1411 ("Unknown/User defined exception");
1413 if (!EnterConditionMet
)
1415 return ContinueType
;
1418 DbgPrint("Entered debugger on %s-chance exception number %d (%s)\n",
1419 FirstChance
? "first" : "last", ExpNr
, ExceptionString
);
1422 /* FIXME: Add noexec memory stuff */
1425 asm volatile("movl %%cr2, %0" : "=r"(Cr2
));
1426 Err
= TrapFrame
->ErrorCode
;
1427 DbgPrint("Memory at 0x%p could not be %s: ", Cr2
, (Err
& (1 << 1)) ? "written" : "read");
1428 if ((Err
& (1 << 0)) == 0)
1429 DbgPrint("Page not present.\n");
1432 if ((Err
& (1 << 3)) != 0)
1433 DbgPrint("Reserved bits in page directory set.\n");
1435 DbgPrint("Page protection violation.\n");
1440 /* Once we enter the debugger we do not expect any more single steps to happen */
1441 KdbNumSingleSteps
= 0;
1443 /* Update the current process pointer */
1444 KdbCurrentProcess
= KdbOriginalProcess
= PsGetCurrentProcess();
1445 KdbCurrentThread
= KdbOriginalThread
= PsGetCurrentThread();
1446 KdbCurrentTrapFrame
= &KdbTrapFrame
;
1448 /* Setup the KDB trap frame */
1449 KdbpTrapFrameToKdbTrapFrame(TrapFrame
, &KdbTrapFrame
);
1451 /* Enter critical section */
1452 Ke386SaveFlags(OldEflags
);
1453 Ke386DisableInterrupts();
1455 /* Exception inside the debugger? Game over. */
1456 if (InterlockedIncrement(&KdbEntryCount
) > 1)
1458 Ke386RestoreFlags(OldEflags
);
1459 return kdHandleException
;
1462 /* Call the main loop. */
1463 KdbpInternalEnter();
1465 /* Check if we should single step */
1466 if (KdbNumSingleSteps
> 0)
1468 if ((KdbSingleStepOver
&& KdbpStepOverInstruction(KdbCurrentTrapFrame
->Tf
.Eip
)) ||
1469 (!KdbSingleStepOver
&& KdbpStepIntoInstruction(KdbCurrentTrapFrame
->Tf
.Eip
)))
1471 ASSERT((KdbCurrentTrapFrame
->Tf
.Eflags
& X86_EFLAGS_TF
) == 0);
1472 /*KdbCurrentTrapFrame->Tf.Eflags &= ~X86_EFLAGS_TF;*/
1476 KdbCurrentTrapFrame
->Tf
.Eflags
|= X86_EFLAGS_TF
;
1480 /* Save the current thread's trapframe */
1481 if (KdbCurrentTrapFrame
== &KdbThreadTrapFrame
)
1483 KdbpKdbTrapFrameToTrapFrame(KdbCurrentTrapFrame
, KdbCurrentThread
->Tcb
.TrapFrame
);
1486 /* Detach from attached process */
1487 if (KdbCurrentProcess
!= KdbOriginalProcess
)
1489 KeUnstackDetachProcess(&KdbApcState
);
1492 /* Update the exception TrapFrame */
1493 KdbpKdbTrapFrameToTrapFrame(&KdbTrapFrame
, TrapFrame
);
1495 /* Decrement the entry count */
1496 InterlockedDecrement(&KdbEntryCount
);
1498 /* Leave critical section */
1499 Ke386RestoreFlags(OldEflags
);
1502 /* Clear debug status */
1503 if (ExpNr
== 1 || ExpNr
== 3) /* FIXME: Why clear DR6 on INT3? */
1505 /* Set the RF flag so we don't trigger the same breakpoint again. */
1508 TrapFrame
->Eflags
|= X86_EFLAGS_RF
;
1511 /* Clear dr6 status flags. */
1512 TrapFrame
->Dr6
&= ~0x0000e00f;
1516 return ContinueType
;
1520 KdbDeleteProcessHook(IN PEPROCESS Process
)
1522 KdbSymFreeProcessSymbols(Process
);
1524 /* FIXME: Delete breakpoints for process */
1529 KdbpGetCommandLineSettings(PCHAR p1
)
1533 while (p1
&& (p2
= strchr(p1
, '/')))
1537 if (!_strnicmp(p2
, "KDSERIAL", 8))
1540 KdbDebugState
|= KD_DEBUG_KDSERIAL
;
1541 KdpDebugMode
.Serial
= TRUE
;
1543 else if (!_strnicmp(p2
, "KDNOECHO", 8))
1546 KdbDebugState
|= KD_DEBUG_KDNOECHO
;