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 /* DEFINES *******************************************************************/
20 #define KDB_STACK_SIZE (4096*3)
21 #define KDB_MAXIMUM_BREAKPOINT_COUNT 256
22 #define KDB_MAXIMUM_HW_BREAKPOINT_COUNT 4
23 #define KDB_MAXIMUM_SW_BREAKPOINT_COUNT 256
25 #define __STRING(x) #x
26 #define _STRING(x) __STRING(x)
28 /* GLOBALS *******************************************************************/
30 STATIC LONG KdbEntryCount
= 0;
31 STATIC CHAR KdbStack
[KDB_STACK_SIZE
];
33 STATIC ULONG KdbBreakPointCount
= 0; /* Number of used breakpoints in the array */
34 STATIC KDB_BREAKPOINT KdbBreakPoints
[KDB_MAXIMUM_BREAKPOINT_COUNT
] = {{0}}; /* Breakpoint array */
35 STATIC ULONG KdbSwBreakPointCount
= 0; /* Number of enabled software breakpoints */
36 STATIC ULONG KdbHwBreakPointCount
= 0; /* Number of enabled hardware breakpoints */
37 STATIC PKDB_BREAKPOINT KdbSwBreakPoints
[KDB_MAXIMUM_SW_BREAKPOINT_COUNT
]; /* Enabled software breakpoints, orderless */
38 STATIC PKDB_BREAKPOINT KdbHwBreakPoints
[KDB_MAXIMUM_HW_BREAKPOINT_COUNT
]; /* Enabled hardware breakpoints, orderless */
39 STATIC PKDB_BREAKPOINT KdbBreakPointToReenable
= NULL
; /* Set to a breakpoint struct when single stepping after
40 a software breakpoint was hit, to reenable it */
41 LONG KdbLastBreakPointNr
= -1; /* Index of the breakpoint which cause KDB to be entered */
42 ULONG KdbNumSingleSteps
= 0; /* How many single steps to do */
43 BOOLEAN KdbSingleStepOver
= FALSE
; /* Whether to step over calls/reps. */
44 ULONG KdbDebugState
= 0; /* KDBG Settings (NOECHO, KDSERIAL) */
45 STATIC BOOLEAN KdbEnteredOnSingleStep
= FALSE
; /* Set to true when KDB was entered because of single step */
46 PEPROCESS KdbCurrentProcess
= NULL
; /* The current process context in which KDB runs */
47 PEPROCESS KdbOriginalProcess
= NULL
; /* The process in whichs context KDB was intered */
48 PETHREAD KdbCurrentThread
= NULL
; /* The current thread context in which KDB runs */
49 PETHREAD KdbOriginalThread
= NULL
; /* The thread in whichs context KDB was entered */
50 PKDB_KTRAP_FRAME KdbCurrentTrapFrame
= NULL
; /* Pointer to the current trapframe */
51 STATIC KDB_KTRAP_FRAME KdbTrapFrame
= { { 0 } }; /* The trapframe which was passed to KdbEnterDebuggerException */
52 STATIC KDB_KTRAP_FRAME KdbThreadTrapFrame
= { { 0 } }; /* The trapframe of the current thread (KdbCurrentThread) */
53 STATIC KAPC_STATE KdbApcState
;
55 /* Array of conditions when to enter KDB */
56 STATIC KDB_ENTER_CONDITION KdbEnterConditions
[][2] =
58 /* First chance Last chance */
59 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* Zero devide */
60 { KdbEnterFromKmode
, KdbDoNotEnter
}, /* Debug trap */
61 { KdbDoNotEnter
, KdbEnterAlways
}, /* NMI */
62 { KdbEnterFromKmode
, KdbDoNotEnter
}, /* INT3 */
63 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* Overflow */
64 { KdbDoNotEnter
, KdbEnterFromKmode
},
65 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* Invalid opcode */
66 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* No math coprocessor fault */
67 { KdbEnterAlways
, KdbEnterAlways
},
68 { KdbEnterAlways
, KdbEnterAlways
},
69 { KdbDoNotEnter
, KdbEnterFromKmode
},
70 { KdbDoNotEnter
, KdbEnterFromKmode
},
71 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* Stack fault */
72 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* General protection fault */
73 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* Page fault */
74 { KdbEnterAlways
, KdbEnterAlways
}, /* Reserved (15) */
75 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* FPU fault */
76 { KdbDoNotEnter
, KdbEnterFromKmode
},
77 { KdbDoNotEnter
, KdbEnterFromKmode
},
78 { KdbDoNotEnter
, KdbEnterFromKmode
}, /* SIMD fault */
79 { KdbDoNotEnter
, KdbEnterFromKmode
} /* Last entry: used for unknown exceptions */
82 /* Exception descriptions */
83 STATIC CONST CHAR
*ExceptionNrToString
[] =
90 "BOUND range exceeded",
92 "No Math Coprocessor",
96 "Segment Not Present",
97 "Stack Segment Fault",
109 KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame
);
113 KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame
);
117 KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame
,
122 KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame
,
125 /* ROS Internal. Please deprecate */
129 HalReleaseDisplayOwnership(
133 /* FUNCTIONS *****************************************************************/
136 KdbpTrapFrameToKdbTrapFrame(PKTRAP_FRAME TrapFrame
, PKDB_KTRAP_FRAME KdbTrapFrame
)
138 ULONG TrapCr0
, TrapCr2
, TrapCr3
, TrapCr4
;
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
));
147 "movl %%cr0, %0" "\n\t"
148 "movl %%cr2, %1" "\n\t"
149 "movl %%cr3, %2" "\n\t"
150 "movl %%cr4, %3" "\n\t"
151 : "=r"(TrapCr0
), "=r"(TrapCr2
),
152 "=r"(TrapCr3
), "=r"(TrapCr4
));
164 /* FIXME: What's the problem with cr4? */
170 KdbTrapFrame
->Cr0
= TrapCr0
;
171 KdbTrapFrame
->Cr2
= TrapCr2
;
172 KdbTrapFrame
->Cr3
= TrapCr3
;
173 KdbTrapFrame
->Cr4
= TrapCr4
;
175 KdbTrapFrame
->Tf
.HardwareEsp
= KiEspFromTrapFrame(TrapFrame
);
176 KdbTrapFrame
->Tf
.HardwareSegSs
= (USHORT
)(KiSsFromTrapFrame(TrapFrame
) & 0xFFFF);
179 /* FIXME: copy v86 registers if TrapFrame is a V86 trapframe */
183 KdbpKdbTrapFrameToTrapFrame(PKDB_KTRAP_FRAME KdbTrapFrame
, PKTRAP_FRAME TrapFrame
)
185 /* Copy the TrapFrame only up to Eflags and zero the rest*/
186 RtlCopyMemory(TrapFrame
, &KdbTrapFrame
->Tf
, FIELD_OFFSET(KTRAP_FRAME
, HardwareEsp
));
188 /* FIXME: write cr0, cr2, cr3 and cr4 (not needed atm) */
190 KiSsToTrapFrame(TrapFrame
, KdbTrapFrame
->Tf
.HardwareSegSs
);
191 KiEspToTrapFrame(TrapFrame
, KdbTrapFrame
->Tf
.HardwareEsp
);
193 /* FIXME: copy v86 registers if TrapFrame is a V86 trapframe */
197 KdbpKdbTrapFrameFromKernelStack(PVOID KernelStack
,
198 PKDB_KTRAP_FRAME KdbTrapFrame
)
202 RtlZeroMemory(KdbTrapFrame
, sizeof(KDB_KTRAP_FRAME
));
203 StackPtr
= (ULONG_PTR
*) KernelStack
;
204 KdbTrapFrame
->Tf
.Ebp
= StackPtr
[3];
205 KdbTrapFrame
->Tf
.Edi
= StackPtr
[4];
206 KdbTrapFrame
->Tf
.Esi
= StackPtr
[5];
207 KdbTrapFrame
->Tf
.Ebx
= StackPtr
[6];
208 KdbTrapFrame
->Tf
.Eip
= StackPtr
[7];
209 KdbTrapFrame
->Tf
.HardwareEsp
= (ULONG
) (StackPtr
+ 8);
210 KdbTrapFrame
->Tf
.HardwareSegSs
= KGDT_R0_DATA
;
211 KdbTrapFrame
->Tf
.SegCs
= KGDT_R0_CODE
;
212 KdbTrapFrame
->Tf
.SegDs
= KGDT_R0_DATA
;
213 KdbTrapFrame
->Tf
.SegEs
= KGDT_R0_DATA
;
214 KdbTrapFrame
->Tf
.SegGs
= KGDT_R0_DATA
;
216 /* FIXME: what about the other registers??? */
219 /*!\brief Overwrites the instruction at \a Address with \a NewInst and stores
220 * the old instruction in *OldInst.
222 * \param Process Process in which's context to overwrite the instruction.
223 * \param Address Address at which to overwrite the instruction.
224 * \param NewInst New instruction (written to \a Address)
225 * \param OldInst Old instruction (read from \a Address)
230 KdbpOverwriteInstruction(
231 IN PEPROCESS Process
,
232 IN ULONG_PTR Address
,
234 OUT PUCHAR OldInst OPTIONAL
)
238 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
241 /* Get the protection for the address. */
242 Protect
= MmGetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
));
244 /* Return if that page isn't present. */
245 if (Protect
& PAGE_NOACCESS
)
247 return STATUS_MEMORY_NOT_ALLOCATED
;
250 /* Attach to the process */
251 if (CurrentProcess
!= Process
)
253 KeStackAttachProcess(&Process
->Pcb
, &ApcState
);
256 /* Make the page writeable if it is read only. */
257 if (Protect
& (PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
))
259 MmSetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
),
260 (Protect
& ~(PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
)) | PAGE_READWRITE
);
263 /* Copy the old instruction back to the caller. */
266 Status
= KdbpSafeReadMemory(OldInst
, (PUCHAR
)Address
, 1);
267 if (!NT_SUCCESS(Status
))
269 if (Protect
& (PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
))
271 MmSetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
), Protect
);
273 /* Detach from process */
274 if (CurrentProcess
!= Process
)
282 /* Copy the new instruction in its place. */
283 Status
= KdbpSafeWriteMemory((PUCHAR
)Address
, &NewInst
, 1);
285 /* Restore the page protection. */
286 if (Protect
& (PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
))
288 MmSetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
), Protect
);
291 /* Detach from process */
292 if (CurrentProcess
!= Process
)
294 KeUnstackDetachProcess(&ApcState
);
300 /*!\brief Checks whether the given instruction can be single stepped or has to be
301 * stepped over using a temporary breakpoint.
303 * \retval TRUE Instruction is a call.
304 * \retval FALSE Instruction is not a call.
307 KdbpShouldStepOverInstruction(ULONG_PTR Eip
)
312 if (!NT_SUCCESS(KdbpSafeReadMemory(Mem
, (PVOID
)Eip
, sizeof (Mem
))))
314 KdbpPrint("Couldn't access memory at 0x%p\n", Eip
);
318 /* Check if the current instruction is a call. */
319 while ((i
< sizeof (Mem
)) && (Mem
[i
] == 0x66 || Mem
[i
] == 0x67))
321 if (i
== sizeof (Mem
))
323 if (Mem
[i
] == 0xE8 || Mem
[i
] == 0x9A || Mem
[i
] == 0xF2 || Mem
[i
] == 0xF3 ||
324 (((i
+ 1) < sizeof (Mem
)) && Mem
[i
] == 0xFF && (Mem
[i
+1] & 0x38) == 0x10))
331 /*!\brief Steps over an instruction
333 * If the given instruction should be stepped over, this function inserts a
334 * temporary breakpoint after the instruction and returns TRUE, otherwise it
337 * \retval TRUE Temporary breakpoint set after instruction.
338 * \retval FALSE No breakpoint was set.
341 KdbpStepOverInstruction(ULONG_PTR Eip
)
345 if (!KdbpShouldStepOverInstruction(Eip
))
348 InstLen
= KdbpGetInstLength(Eip
);
352 if (!NT_SUCCESS(KdbpInsertBreakPoint(Eip
+ InstLen
, KdbBreakPointTemporary
, 0, 0, NULL
, FALSE
, NULL
)))
358 /*!\brief Steps into an instruction (interrupts)
360 * If the given instruction should be stepped into, this function inserts a
361 * temporary breakpoint at the target instruction and returns TRUE, otherwise it
364 * \retval TRUE Temporary breakpoint set at target instruction.
365 * \retval FALSE No breakpoint was set.
368 KdbpStepIntoInstruction(ULONG_PTR Eip
)
370 KDESCRIPTOR Idtr
= {0};
377 if (!NT_SUCCESS(KdbpSafeReadMemory(Mem
, (PVOID
)Eip
, sizeof (Mem
))))
379 /*KdbpPrint("Couldn't access memory at 0x%p\n", Eip);*/
383 /* Check for INT instruction */
384 /* FIXME: Check for iret */
387 else if (Mem
[0] == 0xcd)
389 else if (Mem
[0] == 0xce && KdbCurrentTrapFrame
->Tf
.EFlags
& (1<<11)) /* 1 << 11 is the overflow flag */
394 if (IntVect
< 32) /* We should be informed about interrupts < 32 by the kernel, no need to breakpoint them */
399 /* Read the interrupt descriptor table register */
400 Ke386GetInterruptDescriptorTable(*(PKDESCRIPTOR
)&Idtr
.Limit
);
401 if (IntVect
>= (Idtr
.Limit
+ 1) / 8)
403 /*KdbpPrint("IDT does not contain interrupt vector %d\n.", IntVect);*/
407 /* Get the interrupt descriptor */
408 if (!NT_SUCCESS(KdbpSafeReadMemory(IntDesc
, (PVOID
)(Idtr
.Base
+ (IntVect
* 8)), sizeof (IntDesc
))))
410 /*KdbpPrint("Couldn't access memory at 0x%p\n", (ULONG_PTR)Idtr.Base + (IntVect * 8));*/
414 /* Check descriptor and get target eip (16 bit interrupt/trap gates not supported) */
415 if ((IntDesc
[1] & (1 << 15)) == 0) /* not present */
419 if ((IntDesc
[1] & 0x1f00) == 0x0500) /* Task gate */
421 /* FIXME: Task gates not supported */
424 else if (((IntDesc
[1] & 0x1fe0) == 0x0e00) || /* 32 bit Interrupt gate */
425 ((IntDesc
[1] & 0x1fe0) == 0x0f00)) /* 32 bit Trap gate */
427 /* FIXME: Should the segment selector of the interrupt gate be checked? */
428 TargetEip
= (IntDesc
[1] & 0xffff0000) | (IntDesc
[0] & 0x0000ffff);
435 /* Insert breakpoint */
436 if (!NT_SUCCESS(KdbpInsertBreakPoint(TargetEip
, KdbBreakPointTemporary
, 0, 0, NULL
, FALSE
, NULL
)))
442 /*!\brief Gets the number of the next breakpoint >= Start.
444 * \param Start Breakpoint number to start searching at. -1 if no more breakpoints are found.
446 * \returns Breakpoint number (-1 if no more breakpoints are found)
449 KdbpGetNextBreakPointNr(
450 IN ULONG Start OPTIONAL
)
452 for (; Start
< RTL_NUMBER_OF(KdbBreakPoints
); Start
++)
454 if (KdbBreakPoints
[Start
].Type
!= KdbBreakPointNone
)
460 /*!\brief Returns information of the specified breakpoint.
462 * \param BreakPointNr Number of the breakpoint to return information of.
463 * \param Address Receives the address of the breakpoint.
464 * \param Type Receives the type of the breakpoint (hardware or software)
465 * \param Size Size - for memory breakpoints.
466 * \param AccessType Access type - for hardware breakpoints.
467 * \param DebugReg Debug register - for enabled hardware breakpoints.
468 * \param Enabled Whether the breakpoint is enabled or not.
469 * \param Process The owning process of the breakpoint.
470 * \param ConditionExpression The expression which was given as condition for the bp.
472 * \returns NULL on failure, pointer to a KDB_BREAKPOINT struct on success.
475 KdbpGetBreakPointInfo(
476 IN ULONG BreakPointNr
,
477 OUT ULONG_PTR
*Address OPTIONAL
,
478 OUT KDB_BREAKPOINT_TYPE
*Type OPTIONAL
,
479 OUT UCHAR
*Size OPTIONAL
,
480 OUT KDB_ACCESS_TYPE
*AccessType OPTIONAL
,
481 OUT UCHAR
*DebugReg OPTIONAL
,
482 OUT BOOLEAN
*Enabled OPTIONAL
,
483 OUT BOOLEAN
*Global OPTIONAL
,
484 OUT PEPROCESS
*Process OPTIONAL
,
485 OUT PCHAR
*ConditionExpression OPTIONAL
)
489 if (BreakPointNr
>= RTL_NUMBER_OF(KdbBreakPoints
) ||
490 KdbBreakPoints
[BreakPointNr
].Type
== KdbBreakPointNone
)
495 bp
= KdbBreakPoints
+ BreakPointNr
;
497 *Address
= bp
->Address
;
500 if (bp
->Type
== KdbBreakPointHardware
)
503 *Size
= bp
->Data
.Hw
.Size
;
504 if (AccessType
!= NULL
)
505 *AccessType
= bp
->Data
.Hw
.AccessType
;
506 if (DebugReg
!= NULL
&& bp
->Enabled
)
507 *DebugReg
= bp
->Data
.Hw
.DebugReg
;
510 *Enabled
= bp
->Enabled
;
512 *Global
= bp
->Global
;
514 *Process
= bp
->Process
;
515 if (ConditionExpression
!= NULL
)
516 *ConditionExpression
= bp
->ConditionExpression
;
521 /*!\brief Inserts a breakpoint into the breakpoint array.
523 * The \a Process of the breakpoint is set to \a KdbCurrentProcess
525 * \param Address Address at which to set the breakpoint.
526 * \param Type Type of breakpoint (hardware or software)
527 * \param Size Size of breakpoint (for hardware/memory breakpoints)
528 * \param AccessType Access type (for hardware breakpoins)
529 * \param ConditionExpression Expression which must evaluate to true for conditional breakpoints.
530 * \param Global Wether the breakpoint is global or local to a process.
531 * \param BreakPointNumber Receives the breakpoint number on success
536 KdbpInsertBreakPoint(
537 IN ULONG_PTR Address
,
538 IN KDB_BREAKPOINT_TYPE Type
,
539 IN UCHAR Size OPTIONAL
,
540 IN KDB_ACCESS_TYPE AccessType OPTIONAL
,
541 IN PCHAR ConditionExpression OPTIONAL
,
543 OUT PLONG BreakPointNr OPTIONAL
)
547 PCHAR ConditionExpressionDup
;
551 ASSERT(Type
!= KdbBreakPointNone
);
553 if (Type
== KdbBreakPointHardware
)
555 if ((Address
% Size
) != 0)
557 KdbpPrint("Address (0x%p) must be aligned to a multiple of the size (%d)\n", Address
, Size
);
558 return STATUS_UNSUCCESSFUL
;
560 if (AccessType
== KdbAccessExec
&& Size
!= 1)
562 KdbpPrint("Size must be 1 for execution breakpoints.\n");
563 return STATUS_UNSUCCESSFUL
;
567 if (KdbBreakPointCount
== KDB_MAXIMUM_BREAKPOINT_COUNT
)
569 return STATUS_UNSUCCESSFUL
;
572 /* Parse conditon expression string and duplicate it */
573 if (ConditionExpression
!= NULL
)
575 Condition
= KdbpRpnParseExpression(ConditionExpression
, &ErrOffset
, ErrMsg
);
576 if (Condition
== NULL
)
579 KdbpPrint("Couldn't parse expression: %s at character %d\n", ErrMsg
, ErrOffset
);
581 KdbpPrint("Couldn't parse expression: %s", ErrMsg
);
582 return STATUS_UNSUCCESSFUL
;
585 i
= strlen(ConditionExpression
) + 1;
586 ConditionExpressionDup
= ExAllocatePoolWithTag(NonPagedPool
, i
, TAG_KDBG
);
587 RtlCopyMemory(ConditionExpressionDup
, ConditionExpression
, i
);
593 ConditionExpressionDup
= NULL
;
596 /* Find unused breakpoint */
597 if (Type
== KdbBreakPointTemporary
)
599 for (i
= RTL_NUMBER_OF(KdbBreakPoints
) - 1; i
>= 0; i
--)
601 if (KdbBreakPoints
[i
].Type
== KdbBreakPointNone
)
607 for (i
= 0; i
< (LONG
)RTL_NUMBER_OF(KdbBreakPoints
); i
++)
609 if (KdbBreakPoints
[i
].Type
== KdbBreakPointNone
)
613 ASSERT(i
< (LONG
)RTL_NUMBER_OF(KdbBreakPoints
));
615 /* Set the breakpoint */
616 ASSERT(KdbCurrentProcess
!= NULL
);
617 KdbBreakPoints
[i
].Type
= Type
;
618 KdbBreakPoints
[i
].Address
= Address
;
619 KdbBreakPoints
[i
].Enabled
= FALSE
;
620 KdbBreakPoints
[i
].Global
= Global
;
621 KdbBreakPoints
[i
].Process
= KdbCurrentProcess
;
622 KdbBreakPoints
[i
].ConditionExpression
= ConditionExpressionDup
;
623 KdbBreakPoints
[i
].Condition
= Condition
;
624 if (Type
== KdbBreakPointHardware
)
627 KdbBreakPoints
[i
].Data
.Hw
.Size
= Size
;
628 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 */
639 if (BreakPointNr
!= NULL
)
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)
660 ASSERT(BreakPoint
!= NULL
);
661 BreakPointNr
= BreakPoint
- KdbBreakPoints
;
663 if (BreakPointNr
< 0 || BreakPointNr
>= KDB_MAXIMUM_BREAKPOINT_COUNT
)
665 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
668 if (BreakPoint
== NULL
)
670 BreakPoint
= KdbBreakPoints
+ BreakPointNr
;
672 if (BreakPoint
->Type
== KdbBreakPointNone
)
674 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
678 if (BreakPoint
->Enabled
&&
679 !KdbpDisableBreakPoint(-1, BreakPoint
))
682 if (BreakPoint
->Type
!= KdbBreakPointTemporary
)
683 KdbpPrint("Breakpoint %d deleted.\n", BreakPointNr
);
684 BreakPoint
->Type
= KdbBreakPointNone
;
685 KdbBreakPointCount
--;
690 /*!\brief Checks if the breakpoint was set by the debugger
692 * Tries to find a breakpoint in the breakpoint array which caused
693 * the debug exception to happen.
695 * \param ExpNr Exception Number (1 or 3)
696 * \param TrapFrame Exception trapframe
698 * \returns Breakpoint number, -1 on error.
701 KdbpIsBreakPointOurs(
702 IN NTSTATUS ExceptionCode
,
703 IN PKTRAP_FRAME TrapFrame
)
706 ASSERT(ExceptionCode
== STATUS_SINGLE_STEP
|| ExceptionCode
== STATUS_BREAKPOINT
);
708 if (ExceptionCode
== STATUS_BREAKPOINT
) /* Software interrupt */
710 ULONG_PTR BpEip
= (ULONG_PTR
)TrapFrame
->Eip
- 1; /* Get EIP of INT3 instruction */
711 for (i
= 0; i
< KdbSwBreakPointCount
; i
++)
713 ASSERT((KdbSwBreakPoints
[i
]->Type
== KdbBreakPointSoftware
||
714 KdbSwBreakPoints
[i
]->Type
== KdbBreakPointTemporary
));
715 ASSERT(KdbSwBreakPoints
[i
]->Enabled
);
716 if (KdbSwBreakPoints
[i
]->Address
== BpEip
)
718 return KdbSwBreakPoints
[i
] - KdbBreakPoints
;
722 else if (ExceptionCode
== STATUS_SINGLE_STEP
) /* Hardware interrupt */
725 for (i
= 0; i
< KdbHwBreakPointCount
; i
++)
727 ASSERT(KdbHwBreakPoints
[i
]->Type
== KdbBreakPointHardware
&&
728 KdbHwBreakPoints
[i
]->Enabled
);
729 DebugReg
= KdbHwBreakPoints
[i
]->Data
.Hw
.DebugReg
;
730 if ((TrapFrame
->Dr6
& (1 << DebugReg
)) != 0)
732 return KdbHwBreakPoints
[i
] - KdbBreakPoints
;
740 /*!\brief Enables a breakpoint.
742 * \param BreakPointNr Number of the breakpoint to enable Can be -1.
743 * \param BreakPoint Breakpoint to enable. Can be NULL.
745 * \retval TRUE Success.
746 * \retval FALSE Failure.
748 * \sa KdbpDisableBreakPoint
751 KdbpEnableBreakPoint(
752 IN LONG BreakPointNr OPTIONAL
,
753 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL
)
759 if (BreakPointNr
< 0)
761 ASSERT(BreakPoint
!= NULL
);
762 BreakPointNr
= BreakPoint
- KdbBreakPoints
;
764 if (BreakPointNr
< 0 || BreakPointNr
>= KDB_MAXIMUM_BREAKPOINT_COUNT
)
766 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
769 if (BreakPoint
== NULL
)
771 BreakPoint
= KdbBreakPoints
+ BreakPointNr
;
773 if (BreakPoint
->Type
== KdbBreakPointNone
)
775 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
779 if (BreakPoint
->Enabled
== TRUE
)
781 KdbpPrint("Breakpoint %d is already enabled.\n", BreakPointNr
);
785 if (BreakPoint
->Type
== KdbBreakPointSoftware
||
786 BreakPoint
->Type
== KdbBreakPointTemporary
)
788 if (KdbSwBreakPointCount
>= KDB_MAXIMUM_SW_BREAKPOINT_COUNT
)
790 KdbpPrint("Maximum number of SW breakpoints (%d) used. "
791 "Disable another breakpoint in order to enable this one.\n",
792 KDB_MAXIMUM_SW_BREAKPOINT_COUNT
);
795 Status
= KdbpOverwriteInstruction(BreakPoint
->Process
, BreakPoint
->Address
,
796 0xCC, &BreakPoint
->Data
.SavedInstruction
);
797 if (!NT_SUCCESS(Status
))
799 KdbpPrint("Couldn't access memory at 0x%p\n", BreakPoint
->Address
);
802 KdbSwBreakPoints
[KdbSwBreakPointCount
++] = BreakPoint
;
806 if (BreakPoint
->Data
.Hw
.AccessType
== KdbAccessExec
)
807 ASSERT(BreakPoint
->Data
.Hw
.Size
== 1);
808 ASSERT((BreakPoint
->Address
% BreakPoint
->Data
.Hw
.Size
) == 0);
809 if (KdbHwBreakPointCount
>= KDB_MAXIMUM_HW_BREAKPOINT_COUNT
)
811 KdbpPrint("Maximum number of HW breakpoints (%d) already used. "
812 "Disable another breakpoint in order to enable this one.\n",
813 KDB_MAXIMUM_HW_BREAKPOINT_COUNT
);
817 /* Find unused hw breakpoint */
818 ASSERT(KDB_MAXIMUM_HW_BREAKPOINT_COUNT
== 4);
819 for (i
= 0; i
< KDB_MAXIMUM_HW_BREAKPOINT_COUNT
; i
++)
821 if ((KdbTrapFrame
.Tf
.Dr7
& (0x3 << (i
* 2))) == 0)
824 ASSERT(i
< KDB_MAXIMUM_HW_BREAKPOINT_COUNT
);
826 /* Set the breakpoint address. */
830 KdbTrapFrame
.Tf
.Dr0
= BreakPoint
->Address
;
833 KdbTrapFrame
.Tf
.Dr1
= BreakPoint
->Address
;
836 KdbTrapFrame
.Tf
.Dr2
= BreakPoint
->Address
;
839 KdbTrapFrame
.Tf
.Dr3
= BreakPoint
->Address
;
843 /* Enable the global breakpoint */
844 KdbTrapFrame
.Tf
.Dr7
|= (0x2 << (i
* 2));
846 /* Enable the exact match bits. */
847 KdbTrapFrame
.Tf
.Dr7
|= 0x00000300;
849 /* Clear existing state. */
850 KdbTrapFrame
.Tf
.Dr7
&= ~(0xF << (16 + (i
* 4)));
852 /* Set the breakpoint type. */
853 switch (BreakPoint
->Data
.Hw
.AccessType
)
862 case KdbAccessReadWrite
:
870 KdbTrapFrame
.Tf
.Dr7
|= (ul
<< (16 + (i
* 4)));
872 /* Set the breakpoint length. */
873 KdbTrapFrame
.Tf
.Dr7
|= ((BreakPoint
->Data
.Hw
.Size
- 1) << (18 + (i
* 4)));
875 /* Update KdbCurrentTrapFrame - values are taken from there by the CLI */
876 if (&KdbTrapFrame
!= KdbCurrentTrapFrame
)
878 KdbCurrentTrapFrame
->Tf
.Dr0
= KdbTrapFrame
.Tf
.Dr0
;
879 KdbCurrentTrapFrame
->Tf
.Dr1
= KdbTrapFrame
.Tf
.Dr1
;
880 KdbCurrentTrapFrame
->Tf
.Dr2
= KdbTrapFrame
.Tf
.Dr2
;
881 KdbCurrentTrapFrame
->Tf
.Dr3
= KdbTrapFrame
.Tf
.Dr3
;
882 KdbCurrentTrapFrame
->Tf
.Dr6
= KdbTrapFrame
.Tf
.Dr6
;
883 KdbCurrentTrapFrame
->Tf
.Dr7
= KdbTrapFrame
.Tf
.Dr7
;
886 BreakPoint
->Data
.Hw
.DebugReg
= i
;
887 KdbHwBreakPoints
[KdbHwBreakPointCount
++] = BreakPoint
;
890 BreakPoint
->Enabled
= TRUE
;
891 if (BreakPoint
->Type
!= KdbBreakPointTemporary
)
892 KdbpPrint("Breakpoint %d enabled.\n", BreakPointNr
);
896 /*!\brief Disables a breakpoint.
898 * \param BreakPointNr Number of the breakpoint to disable. Can be -1
899 * \param BreakPoint Breakpoint to disable. Can be NULL.
901 * \retval TRUE Success.
902 * \retval FALSE Failure.
904 * \sa KdbpEnableBreakPoint
907 KdbpDisableBreakPoint(
908 IN LONG BreakPointNr OPTIONAL
,
909 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL
)
914 if (BreakPointNr
< 0)
916 ASSERT(BreakPoint
!= NULL
);
917 BreakPointNr
= BreakPoint
- KdbBreakPoints
;
919 if (BreakPointNr
< 0 || BreakPointNr
>= KDB_MAXIMUM_BREAKPOINT_COUNT
)
921 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
924 if (BreakPoint
== NULL
)
926 BreakPoint
= KdbBreakPoints
+ BreakPointNr
;
928 if (BreakPoint
->Type
== KdbBreakPointNone
)
930 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
934 if (BreakPoint
->Enabled
== FALSE
)
936 KdbpPrint("Breakpoint %d is not enabled.\n", BreakPointNr
);
940 if (BreakPoint
->Type
== KdbBreakPointSoftware
||
941 BreakPoint
->Type
== KdbBreakPointTemporary
)
943 ASSERT(KdbSwBreakPointCount
> 0);
944 Status
= KdbpOverwriteInstruction(BreakPoint
->Process
, BreakPoint
->Address
,
945 BreakPoint
->Data
.SavedInstruction
, NULL
);
946 if (!NT_SUCCESS(Status
))
948 KdbpPrint("Couldn't restore original instruction.\n");
952 for (i
= 0; i
< KdbSwBreakPointCount
; i
++)
954 if (KdbSwBreakPoints
[i
] == BreakPoint
)
956 KdbSwBreakPoints
[i
] = KdbSwBreakPoints
[--KdbSwBreakPointCount
];
957 i
= -1; /* if the last breakpoint is disabled dont break with i >= KdbSwBreakPointCount */
961 if (i
!= (ULONG
)-1) /* not found */
966 ASSERT(BreakPoint
->Type
== KdbBreakPointHardware
);
968 /* Clear the breakpoint. */
969 KdbTrapFrame
.Tf
.Dr7
&= ~(0x3 << (BreakPoint
->Data
.Hw
.DebugReg
* 2));
970 if ((KdbTrapFrame
.Tf
.Dr7
& 0xFF) == 0)
973 * If no breakpoints are enabled then clear the exact match flags.
975 KdbTrapFrame
.Tf
.Dr7
&= 0xFFFFFCFF;
978 for (i
= 0; i
< KdbHwBreakPointCount
; i
++)
980 if (KdbHwBreakPoints
[i
] == BreakPoint
)
982 KdbHwBreakPoints
[i
] = KdbHwBreakPoints
[--KdbHwBreakPointCount
];
983 i
= -1; /* if the last breakpoint is disabled dont break with i >= KdbHwBreakPointCount */
987 if (i
!= (ULONG
)-1) /* not found */
991 BreakPoint
->Enabled
= FALSE
;
992 if (BreakPoint
->Type
!= KdbBreakPointTemporary
)
993 KdbpPrint("Breakpoint %d disabled.\n", BreakPointNr
);
997 /*!\brief Gets the first or last chance enter-condition for exception nr. \a ExceptionNr
999 * \param ExceptionNr Number of the exception to get condition of.
1000 * \param FirstChance Whether to get first or last chance condition.
1001 * \param Condition Receives the condition setting.
1003 * \retval TRUE Success.
1004 * \retval FALSE Failure (invalid exception nr)
1007 KdbpGetEnterCondition(
1008 IN LONG ExceptionNr
,
1009 IN BOOLEAN FirstChance
,
1010 OUT KDB_ENTER_CONDITION
*Condition
)
1012 if (ExceptionNr
>= (LONG
)RTL_NUMBER_OF(KdbEnterConditions
))
1015 *Condition
= KdbEnterConditions
[ExceptionNr
][FirstChance
? 0 : 1];
1019 /*!\brief Sets the first or last chance enter-condition for exception nr. \a ExceptionNr
1021 * \param ExceptionNr Number of the exception to set condition of (-1 for all)
1022 * \param FirstChance Whether to set first or last chance condition.
1023 * \param Condition The new condition setting.
1025 * \retval TRUE Success.
1026 * \retval FALSE Failure (invalid exception nr)
1029 KdbpSetEnterCondition(
1030 IN LONG ExceptionNr
,
1031 IN BOOLEAN FirstChance
,
1032 IN KDB_ENTER_CONDITION Condition
)
1034 if (ExceptionNr
< 0)
1036 for (ExceptionNr
= 0; ExceptionNr
< (LONG
)RTL_NUMBER_OF(KdbEnterConditions
); ExceptionNr
++)
1038 if (ExceptionNr
== 1 || ExceptionNr
== 8 ||
1039 ExceptionNr
== 9 || ExceptionNr
== 15) /* Reserved exceptions */
1043 KdbEnterConditions
[ExceptionNr
][FirstChance
? 0 : 1] = Condition
;
1048 if (ExceptionNr
>= (LONG
)RTL_NUMBER_OF(KdbEnterConditions
) ||
1049 ExceptionNr
== 1 || ExceptionNr
== 8 || /* Do not allow changing of the debug */
1050 ExceptionNr
== 9 || ExceptionNr
== 15) /* trap or reserved exceptions */
1054 KdbEnterConditions
[ExceptionNr
][FirstChance
? 0 : 1] = Condition
;
1059 /*!\brief Switches to another thread context
1061 * \param ThreadId Id of the thread to switch to.
1063 * \retval TRUE Success.
1064 * \retval FALSE Failure (i.e. invalid thread id)
1070 PETHREAD Thread
= NULL
;
1073 /* Get a pointer to the thread */
1074 if (!NT_SUCCESS(PsLookupThreadByThreadId(ThreadId
, &Thread
)))
1076 KdbpPrint("Invalid thread id: 0x%08x\n", (ULONG
)ThreadId
);
1079 Process
= Thread
->ThreadsProcess
;
1081 if (KeIsExecutingDpc() && Process
!= KdbCurrentProcess
)
1083 KdbpPrint("Cannot attach to thread within another process while executing a DPC.\n");
1087 /* Save the current thread's context (if we previously attached to a thread) */
1088 if (KdbCurrentThread
!= KdbOriginalThread
)
1090 ASSERT(KdbCurrentTrapFrame
== &KdbThreadTrapFrame
);
1091 /* Actually, we can't save the context, there's no guarantee that there
1092 * was a trap frame */
1096 ASSERT(KdbCurrentTrapFrame
== &KdbTrapFrame
);
1099 /* Switch to the thread's context */
1100 if (Thread
!= KdbOriginalThread
)
1102 /* The thread we're attaching to isn't the thread on which we entered
1103 * kdb and so the thread we're attaching to is not running. There
1104 * is no guarantee that it actually has a trap frame. So we have to
1105 * peek directly at the registers which were saved on the stack when the
1106 * thread was preempted in the scheduler */
1107 KdbpKdbTrapFrameFromKernelStack(Thread
->Tcb
.KernelStack
,
1108 &KdbThreadTrapFrame
);
1109 KdbCurrentTrapFrame
= &KdbThreadTrapFrame
;
1111 else /* Switching back to original thread */
1113 KdbCurrentTrapFrame
= &KdbTrapFrame
;
1115 KdbCurrentThread
= Thread
;
1117 /* Attach to the thread's process */
1118 ASSERT(KdbCurrentProcess
== PsGetCurrentProcess());
1119 if (KdbCurrentProcess
!= Process
)
1121 if (KdbCurrentProcess
!= KdbOriginalProcess
) /* detach from previously attached process */
1123 KeUnstackDetachProcess(&KdbApcState
);
1125 if (KdbOriginalProcess
!= Process
)
1127 KeStackAttachProcess(&Process
->Pcb
, &KdbApcState
);
1129 KdbCurrentProcess
= Process
;
1135 /*!\brief Switches to another process/thread context
1137 * This function switches to the first thread in the specified process.
1139 * \param ProcessId Id of the process to switch to.
1141 * \retval TRUE Success.
1142 * \retval FALSE Failure (i.e. invalid process id)
1145 KdbpAttachToProcess(
1148 PEPROCESS Process
= NULL
;
1152 /* Get a pointer to the process */
1153 if (!NT_SUCCESS(PsLookupProcessByProcessId(ProcessId
, &Process
)))
1155 KdbpPrint("Invalid process id: 0x%08x\n", (ULONG
)ProcessId
);
1159 Entry
= Process
->ThreadListHead
.Flink
;
1160 if (Entry
== &KdbCurrentProcess
->ThreadListHead
)
1162 KdbpPrint("No threads in process 0x%08x, cannot attach to process!\n", (ULONG
)ProcessId
);
1166 Thread
= CONTAINING_RECORD(Entry
, ETHREAD
, ThreadListEntry
);
1168 return KdbpAttachToThread(Thread
->Cid
.UniqueThread
);
1171 /*!\brief Calls the main loop ...
1176 KdbpCliMainLoop(KdbEnteredOnSingleStep
);
1179 /*!\brief Internal function to enter KDB.
1181 * Disables interrupts, releases display ownership, ...
1187 PVOID SavedInitialStack
, SavedStackBase
, SavedKernelStack
;
1188 ULONG SavedStackLimit
;
1191 if (KdpDebugMode
.Screen
)
1193 InbvAcquireDisplayOwnership();
1196 /* Call the interface's main loop on a different stack */
1197 Thread
= PsGetCurrentThread();
1198 SavedInitialStack
= Thread
->Tcb
.InitialStack
;
1199 SavedStackBase
= Thread
->Tcb
.StackBase
;
1200 SavedStackLimit
= Thread
->Tcb
.StackLimit
;
1201 SavedKernelStack
= Thread
->Tcb
.KernelStack
;
1202 Thread
->Tcb
.InitialStack
= Thread
->Tcb
.StackBase
= (char*)KdbStack
+ KDB_STACK_SIZE
;
1203 Thread
->Tcb
.StackLimit
= (ULONG
)KdbStack
;
1204 Thread
->Tcb
.KernelStack
= (char*)KdbStack
+ KDB_STACK_SIZE
;
1206 /*KdbpPrint("Switching to KDB stack 0x%08x-0x%08x\n", Thread->Tcb.StackLimit, Thread->Tcb.StackBase);*/
1208 KdbpStackSwitchAndCall(Thread
->Tcb
.KernelStack
, KdbpCallMainLoop
);
1210 Thread
->Tcb
.InitialStack
= SavedInitialStack
;
1211 Thread
->Tcb
.StackBase
= SavedStackBase
;
1212 Thread
->Tcb
.StackLimit
= SavedStackLimit
;
1213 Thread
->Tcb
.KernelStack
= SavedKernelStack
;
1218 KdbpGetExceptionNumberFromStatus(IN NTSTATUS ExceptionCode
)
1222 switch (ExceptionCode
)
1224 case STATUS_INTEGER_DIVIDE_BY_ZERO
:
1227 case STATUS_SINGLE_STEP
:
1230 case STATUS_BREAKPOINT
:
1233 case STATUS_INTEGER_OVERFLOW
:
1236 case STATUS_ARRAY_BOUNDS_EXCEEDED
:
1239 case STATUS_ILLEGAL_INSTRUCTION
:
1242 case STATUS_FLOAT_INVALID_OPERATION
:
1245 case STATUS_STACK_OVERFLOW
:
1248 case STATUS_ACCESS_VIOLATION
:
1251 case STATUS_DATATYPE_MISALIGNMENT
:
1254 case STATUS_FLOAT_MULTIPLE_TRAPS
:
1259 Ret
= RTL_NUMBER_OF(KdbEnterConditions
) - 1;
1266 /*!\brief KDB Exception filter
1268 * Called by the exception dispatcher.
1270 * \param ExceptionRecord Unused.
1271 * \param PreviousMode UserMode if the exception was raised from umode, otherwise KernelMode.
1272 * \param Context Context, IN/OUT parameter.
1273 * \param TrapFrame Exception TrapFrame.
1274 * \param FirstChance TRUE when called before exception frames were serached,
1275 * FALSE for the second call.
1277 * \returns KD_CONTINUE_TYPE
1280 KdbEnterDebuggerException(
1281 IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL
,
1282 IN KPROCESSOR_MODE PreviousMode
,
1283 IN PCONTEXT Context
,
1284 IN OUT PKTRAP_FRAME TrapFrame
,
1285 IN BOOLEAN FirstChance
)
1287 KDB_ENTER_CONDITION EnterCondition
;
1288 KD_CONTINUE_TYPE ContinueType
= kdHandleException
;
1289 PKDB_BREAKPOINT BreakPoint
;
1292 BOOLEAN Resume
= FALSE
;
1293 BOOLEAN EnterConditionMet
= TRUE
;
1295 NTSTATUS ExceptionCode
;
1297 ExceptionCode
= (ExceptionRecord
!= NULL
? ExceptionRecord
->ExceptionCode
: STATUS_BREAKPOINT
);
1299 KdbCurrentProcess
= PsGetCurrentProcess();
1301 /* Set continue type to kdContinue for single steps and breakpoints */
1302 if (ExceptionCode
== STATUS_SINGLE_STEP
|| ExceptionCode
== STATUS_BREAKPOINT
)
1303 ContinueType
= kdContinue
;
1305 /* Check if we should handle the exception. */
1306 /* FIXME - won't get all exceptions here :( */
1307 ExpNr
= KdbpGetExceptionNumberFromStatus(ExceptionCode
);
1308 EnterCondition
= KdbEnterConditions
[ExpNr
][FirstChance
? 0 : 1];
1309 if (EnterCondition
== KdbDoNotEnter
||
1310 (EnterCondition
== KdbEnterFromUmode
&& PreviousMode
== KernelMode
) ||
1311 (EnterCondition
== KdbEnterFromKmode
&& PreviousMode
!= KernelMode
))
1313 EnterConditionMet
= FALSE
;
1316 /* If we stopped on one of our breakpoints then let the user know. */
1317 KdbLastBreakPointNr
= -1;
1318 KdbEnteredOnSingleStep
= FALSE
;
1320 if (FirstChance
&& (ExceptionCode
== STATUS_SINGLE_STEP
|| ExceptionCode
== STATUS_BREAKPOINT
) &&
1321 (KdbLastBreakPointNr
= KdbpIsBreakPointOurs(ExceptionCode
, TrapFrame
)) >= 0)
1323 BreakPoint
= KdbBreakPoints
+ KdbLastBreakPointNr
;
1325 if (ExceptionCode
== STATUS_BREAKPOINT
)
1328 * ... and restore the original instruction.
1330 if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess
, BreakPoint
->Address
,
1331 BreakPoint
->Data
.SavedInstruction
, NULL
)))
1333 DbgPrint("Couldn't restore original instruction after INT3! Cannot continue execution.\n");
1338 if ((BreakPoint
->Type
== KdbBreakPointHardware
) &&
1339 (BreakPoint
->Data
.Hw
.AccessType
== KdbAccessExec
))
1341 Resume
= TRUE
; /* Set the resume flag when continuing execution */
1345 * When a temporary breakpoint is hit we have to make sure that we are
1346 * in the same context in which it was set, otherwise it could happen
1347 * that another process/thread hits it before and it gets deleted.
1349 else if (BreakPoint
->Type
== KdbBreakPointTemporary
&&
1350 BreakPoint
->Process
== KdbCurrentProcess
)
1352 ASSERT((TrapFrame
->EFlags
& X86_EFLAGS_TF
) == 0);
1355 * Delete the temporary breakpoint which was used to step over or into the instruction.
1357 KdbpDeleteBreakPoint(-1, BreakPoint
);
1359 if (--KdbNumSingleSteps
> 0)
1361 if ((KdbSingleStepOver
&& !KdbpStepOverInstruction(TrapFrame
->Eip
)) ||
1362 (!KdbSingleStepOver
&& !KdbpStepIntoInstruction(TrapFrame
->Eip
)))
1364 TrapFrame
->EFlags
|= X86_EFLAGS_TF
;
1366 goto continue_execution
; /* return */
1369 KdbEnteredOnSingleStep
= TRUE
;
1373 * If we hit a breakpoint set by the debugger we set the single step flag,
1374 * ignore the next single step and reenable the breakpoint.
1376 else if (BreakPoint
->Type
== KdbBreakPointSoftware
||
1377 BreakPoint
->Type
== KdbBreakPointTemporary
)
1379 ASSERT(ExceptionCode
== STATUS_BREAKPOINT
);
1380 TrapFrame
->EFlags
|= X86_EFLAGS_TF
;
1381 KdbBreakPointToReenable
= BreakPoint
;
1385 * Make sure that the breakpoint should be triggered in this context
1387 if (!BreakPoint
->Global
&& BreakPoint
->Process
!= KdbCurrentProcess
)
1389 goto continue_execution
; /* return */
1393 * Check if the condition for the breakpoint is met.
1395 if (BreakPoint
->Condition
!= NULL
)
1397 /* Setup the KDB trap frame */
1398 KdbpTrapFrameToKdbTrapFrame(TrapFrame
, &KdbTrapFrame
);
1401 if (!KdbpRpnEvaluateParsedExpression(BreakPoint
->Condition
, &KdbTrapFrame
, &ull
, NULL
, NULL
))
1403 /* FIXME: Print warning? */
1405 else if (ull
== 0) /* condition is not met */
1407 goto continue_execution
; /* return */
1411 if (BreakPoint
->Type
== KdbBreakPointSoftware
)
1413 DbgPrint("Entered debugger on breakpoint #%d: EXEC 0x%04x:0x%08x\n",
1414 KdbLastBreakPointNr
, TrapFrame
->SegCs
& 0xffff, TrapFrame
->Eip
);
1416 else if (BreakPoint
->Type
== KdbBreakPointHardware
)
1418 DbgPrint("Entered debugger on breakpoint #%d: %s 0x%08x\n",
1419 KdbLastBreakPointNr
,
1420 (BreakPoint
->Data
.Hw
.AccessType
== KdbAccessRead
) ? "READ" :
1421 ((BreakPoint
->Data
.Hw
.AccessType
== KdbAccessWrite
) ? "WRITE" :
1422 ((BreakPoint
->Data
.Hw
.AccessType
== KdbAccessReadWrite
) ? "RDWR" : "EXEC")
1429 else if (ExceptionCode
== STATUS_SINGLE_STEP
)
1431 /* Silently ignore a debugger initiated single step. */
1432 if ((TrapFrame
->Dr6
& 0xf) == 0 && KdbBreakPointToReenable
!= NULL
)
1434 /* FIXME: Make sure that the breakpoint was really hit (check bp->Address vs. tf->Eip) */
1435 BreakPoint
= KdbBreakPointToReenable
;
1436 KdbBreakPointToReenable
= NULL
;
1437 ASSERT(BreakPoint
->Type
== KdbBreakPointSoftware
||
1438 BreakPoint
->Type
== KdbBreakPointTemporary
);
1441 * Reenable the breakpoint we disabled to execute the breakpointed
1444 if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess
, BreakPoint
->Address
, 0xCC,
1445 &BreakPoint
->Data
.SavedInstruction
)))
1447 DbgPrint("Warning: Couldn't reenable breakpoint %d\n",
1448 BreakPoint
- KdbBreakPoints
);
1451 /* Unset TF if we are no longer single stepping. */
1452 if (KdbNumSingleSteps
== 0)
1453 TrapFrame
->EFlags
&= ~X86_EFLAGS_TF
;
1454 goto continue_execution
; /* return */
1457 /* Check if we expect a single step */
1458 if ((TrapFrame
->Dr6
& 0xf) == 0 && KdbNumSingleSteps
> 0)
1460 /*ASSERT((TrapFrame->Eflags & X86_EFLAGS_TF) != 0);*/
1461 if (--KdbNumSingleSteps
> 0)
1463 if ((KdbSingleStepOver
&& KdbpStepOverInstruction(TrapFrame
->Eip
)) ||
1464 (!KdbSingleStepOver
&& KdbpStepIntoInstruction(TrapFrame
->Eip
)))
1466 TrapFrame
->EFlags
&= ~X86_EFLAGS_TF
;
1470 TrapFrame
->EFlags
|= X86_EFLAGS_TF
;
1472 goto continue_execution
; /* return */
1475 TrapFrame
->EFlags
&= ~X86_EFLAGS_TF
;
1476 KdbEnteredOnSingleStep
= TRUE
;
1480 if (!EnterConditionMet
)
1482 return kdHandleException
;
1484 DbgPrint("Entered debugger on unexpected debug trap!\n");
1487 else if (ExceptionCode
== STATUS_BREAKPOINT
)
1489 if (KdbInitFileBuffer
!= NULL
)
1491 KdbpCliInterpretInitFile();
1492 EnterConditionMet
= FALSE
;
1494 if (!EnterConditionMet
)
1496 return kdHandleException
;
1499 DbgPrint("Entered debugger on embedded INT3 at 0x%04x:0x%08x.\n",
1500 TrapFrame
->SegCs
& 0xffff, TrapFrame
->Eip
- 1);
1504 CONST CHAR
*ExceptionString
= (ExpNr
< RTL_NUMBER_OF(ExceptionNrToString
)) ?
1505 (ExceptionNrToString
[ExpNr
]) :
1506 ("Unknown/User defined exception");
1508 if (!EnterConditionMet
)
1510 return ContinueType
;
1513 DbgPrint("Entered debugger on %s-chance exception (Exception Code: 0x%x) (%s)\n",
1514 FirstChance
? "first" : "last", ExceptionCode
, ExceptionString
);
1515 if (ExceptionCode
== STATUS_ACCESS_VIOLATION
&&
1516 ExceptionRecord
!= NULL
&& ExceptionRecord
->NumberParameters
!= 0)
1518 /* FIXME: Add noexec memory stuff */
1522 asm volatile("movl %%cr2, %0" : "=r"(TrapCr2
));
1525 __asm mov TrapCr2
, eax
;
1527 #error Unknown compiler for inline assembler
1530 Err
= TrapFrame
->ErrCode
;
1531 DbgPrint("Memory at 0x%p could not be %s: ", TrapCr2
, (Err
& (1 << 1)) ? "written" : "read");
1532 if ((Err
& (1 << 0)) == 0)
1533 DbgPrint("Page not present.\n");
1536 if ((Err
& (1 << 3)) != 0)
1537 DbgPrint("Reserved bits in page directory set.\n");
1539 DbgPrint("Page protection violation.\n");
1544 /* Once we enter the debugger we do not expect any more single steps to happen */
1545 KdbNumSingleSteps
= 0;
1547 /* Update the current process pointer */
1548 KdbCurrentProcess
= KdbOriginalProcess
= PsGetCurrentProcess();
1549 KdbCurrentThread
= KdbOriginalThread
= PsGetCurrentThread();
1550 KdbCurrentTrapFrame
= &KdbTrapFrame
;
1552 /* Setup the KDB trap frame */
1553 KdbpTrapFrameToKdbTrapFrame(TrapFrame
, &KdbTrapFrame
);
1555 /* Enter critical section */
1556 Ke386SaveFlags(OldEflags
);
1559 /* Exception inside the debugger? Game over. */
1560 if (InterlockedIncrement(&KdbEntryCount
) > 1)
1562 Ke386RestoreFlags(OldEflags
);
1563 return kdHandleException
;
1566 /* Call the main loop. */
1567 KdbpInternalEnter();
1569 /* Check if we should single step */
1570 if (KdbNumSingleSteps
> 0)
1572 if ((KdbSingleStepOver
&& KdbpStepOverInstruction(KdbCurrentTrapFrame
->Tf
.Eip
)) ||
1573 (!KdbSingleStepOver
&& KdbpStepIntoInstruction(KdbCurrentTrapFrame
->Tf
.Eip
)))
1575 ASSERT((KdbCurrentTrapFrame
->Tf
.EFlags
& X86_EFLAGS_TF
) == 0);
1576 /*KdbCurrentTrapFrame->Tf.EFlags &= ~X86_EFLAGS_TF;*/
1580 KdbCurrentTrapFrame
->Tf
.EFlags
|= X86_EFLAGS_TF
;
1584 /* We can't update the current thread's trapframe 'cause it might not
1587 /* Detach from attached process */
1588 if (KdbCurrentProcess
!= KdbOriginalProcess
)
1590 KeUnstackDetachProcess(&KdbApcState
);
1593 /* Update the exception TrapFrame */
1594 KdbpKdbTrapFrameToTrapFrame(&KdbTrapFrame
, TrapFrame
);
1596 /* Decrement the entry count */
1597 InterlockedDecrement(&KdbEntryCount
);
1599 /* Leave critical section */
1600 Ke386RestoreFlags(OldEflags
);
1603 /* Clear debug status */
1604 if (ExceptionCode
== STATUS_SINGLE_STEP
|| ExceptionCode
== STATUS_BREAKPOINT
) /* FIXME: Why clear DR6 on INT3? */
1606 /* Set the RF flag so we don't trigger the same breakpoint again. */
1609 TrapFrame
->EFlags
|= X86_EFLAGS_RF
;
1612 /* Clear dr6 status flags. */
1613 TrapFrame
->Dr6
&= ~0x0000e00f;
1615 /* Skip the current instruction */
1619 return ContinueType
;
1623 KdbDeleteProcessHook(IN PEPROCESS Process
)
1625 KdbSymFreeProcessSymbols(Process
);
1627 /* FIXME: Delete breakpoints for process */
1632 KdbpGetCommandLineSettings(PCHAR p1
)
1636 while (p1
&& (p2
= strchr(p1
, ' ')))
1640 if (!_strnicmp(p2
, "KDSERIAL", 8))
1643 KdbDebugState
|= KD_DEBUG_KDSERIAL
;
1644 KdpDebugMode
.Serial
= TRUE
;
1646 else if (!_strnicmp(p2
, "KDNOECHO", 8))
1649 KdbDebugState
|= KD_DEBUG_KDNOECHO
;
1657 KdbpSafeReadMemory(OUT PVOID Dest
,
1661 BOOLEAN Result
= TRUE
;
1669 Result
= KdpSafeReadMemory((ULONG_PTR
)Src
, Bytes
, Dest
);
1673 ULONG_PTR Start
, End
, Write
;
1674 for (Start
= (ULONG_PTR
)Src
,
1675 End
= Start
+ Bytes
,
1676 Write
= (ULONG_PTR
)Dest
;
1677 Result
&& (Start
< End
);
1679 if (!KdpSafeReadMemory(Start
, 1, (PVOID
)Write
))
1685 return Result
? STATUS_SUCCESS
: STATUS_ACCESS_VIOLATION
;
1689 KdbpSafeWriteMemory(OUT PVOID Dest
,
1694 ULONG_PTR Start
, End
, Write
;
1696 for (Start
= (ULONG_PTR
)Src
,
1697 End
= Start
+ Bytes
,
1698 Write
= (ULONG_PTR
)Dest
;
1699 Result
&& (Start
< End
);
1701 if (!KdpSafeReadMemory(Start
, 1, (PVOID
)Write
))
1704 return Result
? STATUS_SUCCESS
: STATUS_ACCESS_VIOLATION
;