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 { KdbEnterAlways
, 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 PCHAR ExceptionNrToString
[] =
90 "BOUND range exceeded",
92 "No Math Coprocessor",
96 "Segment Not Present",
97 "Stack Segment Fault",
107 /* FUNCTIONS *****************************************************************/
110 KdbpTrapFrameToKdbTrapFrame(PKTRAP_FRAME TrapFrame
, PKDB_KTRAP_FRAME KdbTrapFrame
)
112 /* Copy the TrapFrame only up to Eflags and zero the rest*/
113 RtlCopyMemory(&KdbTrapFrame
->Tf
, TrapFrame
, FIELD_OFFSET(KTRAP_FRAME
, Esp
));
114 RtlZeroMemory((PVOID
)((ULONG_PTR
)&KdbTrapFrame
->Tf
+ FIELD_OFFSET(KTRAP_FRAME
, Esp
)),
115 sizeof (KTRAP_FRAME
) - FIELD_OFFSET(KTRAP_FRAME
, Esp
));
117 "movl %%cr0, %0" "\n\t"
118 "movl %%cr2, %1" "\n\t"
119 "movl %%cr3, %2" "\n\t"
120 "movl %%cr4, %3" "\n\t"
121 : "=r"(KdbTrapFrame
->Cr0
), "=r"(KdbTrapFrame
->Cr2
),
122 "=r"(KdbTrapFrame
->Cr3
), "=r"(KdbTrapFrame
->Cr4
));
124 if (TrapFrame
->PreviousMode
== KernelMode
)
126 /* If the trapframe is a kmode one use the temp ss:esp */
127 KdbTrapFrame
->Tf
.Esp
= (ULONG
)TrapFrame
->TempEsp
;
128 KdbTrapFrame
->Tf
.Ss
= (USHORT
)((ULONG
)TrapFrame
->TempSegSs
& 0xFFFF);
132 /* Otherwise use ss:esp pushed by the CPU */
133 /* FIXME: maybe change all trapframes to always put ss:esp into tempss:tempesp so we
134 * can handle umode and kmode the same way */
135 KdbTrapFrame
->Tf
.Esp
= TrapFrame
->Esp
;
136 KdbTrapFrame
->Tf
.Ss
= TrapFrame
->Ss
;
139 /* FIXME: copy v86 registers if TrapFrame is a V86 trapframe */
143 KdbpKdbTrapFrameToTrapFrame(PKDB_KTRAP_FRAME KdbTrapFrame
, PKTRAP_FRAME TrapFrame
)
145 /* Copy the TrapFrame only up to Eflags and zero the rest*/
146 RtlCopyMemory(TrapFrame
, &KdbTrapFrame
->Tf
, FIELD_OFFSET(KTRAP_FRAME
, Esp
));
148 /* FIXME: write cr0, cr2, cr3 and cr4 (not needed atm) */
150 if (TrapFrame
->PreviousMode
== KernelMode
)
152 /* If the trapframe is a kmode one write to the temp ss:esp */
153 TrapFrame
->TempEsp
= (PVOID
)KdbTrapFrame
->Tf
.Esp
;
154 TrapFrame
->TempSegSs
= (PVOID
)(((ULONG
)TrapFrame
->TempSegSs
& ~0xffff) | KdbTrapFrame
->Tf
.Ss
);
158 /* Otherwise write to ss:esp pushed by the CPU */
159 /* FIXME: maybe change all trap-epilogs to always put temp ss:esp into ss:esp so we
160 * can handle umode and kmode the same way */
161 TrapFrame
->Esp
= KdbTrapFrame
->Tf
.Esp
;
162 TrapFrame
->Ss
= KdbTrapFrame
->Tf
.Ss
;
165 /* FIXME: copy v86 registers if TrapFrame is a V86 trapframe */
168 /*!\brief Overwrites the instruction at \a Address with \a NewInst and stores
169 * the old instruction in *OldInst.
171 * \param Process Process in which's context to overwrite the instruction.
172 * \param Address Address at which to overwrite the instruction.
173 * \param NewInst New instruction (written to \a Address)
174 * \param OldInst Old instruction (read from \a Address)
179 KdbpOverwriteInstruction(
180 IN PEPROCESS Process
,
181 IN ULONG_PTR Address
,
183 OUT PUCHAR OldInst OPTIONAL
)
187 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
190 /* Get the protection for the address. */
191 Protect
= MmGetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
));
193 /* Return if that page isn't present. */
194 if (Protect
& PAGE_NOACCESS
)
196 return STATUS_MEMORY_NOT_ALLOCATED
;
199 /* Attach to the process */
200 if (CurrentProcess
!= Process
)
202 KeStackAttachProcess(EPROCESS_TO_KPROCESS(Process
), &ApcState
);
205 /* Make the page writeable if it is read only. */
206 if (Protect
& (PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
))
208 MmSetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
),
209 (Protect
& ~(PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
)) | PAGE_READWRITE
);
212 /* Copy the old instruction back to the caller. */
215 Status
= KdbpSafeReadMemory(OldInst
, (PUCHAR
)Address
, 1);
216 if (!NT_SUCCESS(Status
))
218 if (Protect
& (PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
))
220 MmSetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
), Protect
);
222 /* Detach from process */
223 if (CurrentProcess
!= Process
)
231 /* Copy the new instruction in its place. */
232 Status
= KdbpSafeWriteMemory((PUCHAR
)Address
, &NewInst
, 1);
234 /* Restore the page protection. */
235 if (Protect
& (PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
))
237 MmSetPageProtect(Process
, (PVOID
)PAGE_ROUND_DOWN(Address
), Protect
);
240 /* Detach from process */
241 if (CurrentProcess
!= Process
)
243 KeUnstackDetachProcess(&ApcState
);
249 /*!\brief Checks whether the given instruction can be single stepped or has to be
250 * stepped over using a temporary breakpoint.
252 * \retval TRUE Instruction is a call.
253 * \retval FALSE Instruction is not a call.
256 KdbpShouldStepOverInstruction(ULONG_PTR Eip
)
261 if (!NT_SUCCESS(KdbpSafeReadMemory(Mem
, (PVOID
)Eip
, sizeof (Mem
))))
263 KdbpPrint("Couldn't access memory at 0x%x\n", (UINT
)Eip
);
267 /* Check if the current instruction is a call. */
268 while ((i
< sizeof (Mem
)) && (Mem
[i
] == 0x66 || Mem
[i
] == 0x67))
270 if (i
== sizeof (Mem
))
272 if (Mem
[i
] == 0xE8 || Mem
[i
] == 0x9A || Mem
[i
] == 0xF2 || Mem
[i
] == 0xF3 ||
273 (((i
+ 1) < sizeof (Mem
)) && Mem
[i
] == 0xFF && (Mem
[i
+1] & 0x38) == 0x10))
280 /*!\brief Steps over an instruction
282 * If the given instruction should be stepped over, this function inserts a
283 * temporary breakpoint after the instruction and returns TRUE, otherwise it
286 * \retval TRUE Temporary breakpoint set after instruction.
287 * \retval FALSE No breakpoint was set.
290 KdbpStepOverInstruction(ULONG_PTR Eip
)
294 if (!KdbpShouldStepOverInstruction(Eip
))
297 InstLen
= KdbpGetInstLength(Eip
);
301 if (!NT_SUCCESS(KdbpInsertBreakPoint(Eip
+ InstLen
, KdbBreakPointTemporary
, 0, 0, NULL
, FALSE
, NULL
)))
307 /*!\brief Steps into an instruction (interrupts)
309 * If the given instruction should be stepped into, this function inserts a
310 * temporary breakpoint at the target instruction and returns TRUE, otherwise it
313 * \retval TRUE Temporary breakpoint set at target instruction.
314 * \retval FALSE No breakpoint was set.
317 KdbpStepIntoInstruction(ULONG_PTR Eip
)
319 struct __attribute__((packed
)) {
329 if (!NT_SUCCESS(KdbpSafeReadMemory(Mem
, (PVOID
)Eip
, sizeof (Mem
))))
331 /*KdbpPrint("Couldn't access memory at 0x%x\n", (UINT)Eip);*/
335 /* Check for INT instruction */
336 /* FIXME: Check for iret */
339 else if (Mem
[0] == 0xcd)
341 else if (Mem
[0] == 0xce && KdbCurrentTrapFrame
->Tf
.Eflags
& (1<<11)) /* 1 << 11 is the overflow flag */
346 if (IntVect
< 32) /* We should be informed about interrupts < 32 by the kernel, no need to breakpoint them */
351 /* Read the interrupt descriptor table register */
352 asm volatile("sidt %0" : : "m"(Idtr
));
353 if (IntVect
>= (Idtr
.Limit
+ 1) / 8)
355 /*KdbpPrint("IDT does not contain interrupt vector %d\n.", IntVect);*/
359 /* Get the interrupt descriptor */
360 if (!NT_SUCCESS(KdbpSafeReadMemory(IntDesc
, (PVOID
)(Idtr
.Base
+ (IntVect
* 8)), sizeof (IntDesc
))))
362 /*KdbpPrint("Couldn't access memory at 0x%x\n", (UINT)Idtr.Base + (IntVect * 8));*/
366 /* Check descriptor and get target eip (16 bit interrupt/trap gates not supported) */
367 if ((IntDesc
[1] & (1 << 15)) == 0) /* not present */
371 if ((IntDesc
[1] & 0x1f00) == 0x0500) /* Task gate */
373 /* FIXME: Task gates not supported */
376 else if (((IntDesc
[1] & 0x1fe0) == 0x0e00) || /* 32 bit Interrupt gate */
377 ((IntDesc
[1] & 0x1fe0) == 0x0f00)) /* 32 bit Trap gate */
379 /* FIXME: Should the segment selector of the interrupt gate be checked? */
380 TargetEip
= (IntDesc
[1] & 0xffff0000) | (IntDesc
[0] & 0x0000ffff);
387 /* Insert breakpoint */
388 if (!NT_SUCCESS(KdbpInsertBreakPoint(TargetEip
, KdbBreakPointTemporary
, 0, 0, NULL
, FALSE
, NULL
)))
394 /*!\brief Gets the number of the next breakpoint >= Start.
396 * \param Start Breakpoint number to start searching at. -1 if no more breakpoints are found.
398 * \returns Breakpoint number (-1 if no more breakpoints are found)
401 KdbpGetNextBreakPointNr(
402 IN ULONG Start OPTIONAL
)
404 for (; Start
< RTL_NUMBER_OF(KdbBreakPoints
); Start
++)
406 if (KdbBreakPoints
[Start
].Type
!= KdbBreakPointNone
)
412 /*!\brief Returns information of the specified breakpoint.
414 * \param BreakPointNr Number of the breakpoint to return information of.
415 * \param Address Receives the address of the breakpoint.
416 * \param Type Receives the type of the breakpoint (hardware or software)
417 * \param Size Size - for memory breakpoints.
418 * \param AccessType Access type - for hardware breakpoints.
419 * \param DebugReg Debug register - for enabled hardware breakpoints.
420 * \param Enabled Whether the breakpoint is enabled or not.
421 * \param Process The owning process of the breakpoint.
422 * \param ConditionExpression The expression which was given as condition for the bp.
424 * \returns NULL on failure, pointer to a KDB_BREAKPOINT struct on success.
427 KdbpGetBreakPointInfo(
428 IN ULONG BreakPointNr
,
429 OUT ULONG_PTR
*Address OPTIONAL
,
430 OUT KDB_BREAKPOINT_TYPE
*Type OPTIONAL
,
431 OUT UCHAR
*Size OPTIONAL
,
432 OUT KDB_ACCESS_TYPE
*AccessType OPTIONAL
,
433 OUT UCHAR
*DebugReg OPTIONAL
,
434 OUT BOOLEAN
*Enabled OPTIONAL
,
435 OUT BOOLEAN
*Global OPTIONAL
,
436 OUT PEPROCESS
*Process OPTIONAL
,
437 OUT PCHAR
*ConditionExpression OPTIONAL
)
441 if (BreakPointNr
>= RTL_NUMBER_OF(KdbBreakPoints
) ||
442 KdbBreakPoints
[BreakPointNr
].Type
== KdbBreakPointNone
)
447 bp
= KdbBreakPoints
+ BreakPointNr
;
449 *Address
= bp
->Address
;
452 if (bp
->Type
== KdbBreakPointHardware
)
455 *Size
= bp
->Data
.Hw
.Size
;
456 if (AccessType
!= NULL
)
457 *AccessType
= bp
->Data
.Hw
.AccessType
;
458 if (DebugReg
!= NULL
&& bp
->Enabled
)
459 *DebugReg
= bp
->Data
.Hw
.DebugReg
;
462 *Enabled
= bp
->Enabled
;
464 *Global
= bp
->Global
;
466 *Process
= bp
->Process
;
467 if (ConditionExpression
!= NULL
)
468 *ConditionExpression
= bp
->ConditionExpression
;
473 /*!\brief Inserts a breakpoint into the breakpoint array.
475 * The \a Process of the breakpoint is set to \a KdbCurrentProcess
477 * \param Address Address at which to set the breakpoint.
478 * \param Type Type of breakpoint (hardware or software)
479 * \param Size Size of breakpoint (for hardware/memory breakpoints)
480 * \param AccessType Access type (for hardware breakpoins)
481 * \param ConditionExpression Expression which must evaluate to true for conditional breakpoints.
482 * \param Global Wether the breakpoint is global or local to a process.
483 * \param BreakPointNumber Receives the breakpoint number on success
488 KdbpInsertBreakPoint(
489 IN ULONG_PTR Address
,
490 IN KDB_BREAKPOINT_TYPE Type
,
491 IN UCHAR Size OPTIONAL
,
492 IN KDB_ACCESS_TYPE AccessType OPTIONAL
,
493 IN PCHAR ConditionExpression OPTIONAL
,
495 OUT PULONG BreakPointNumber OPTIONAL
)
499 PCHAR ConditionExpressionDup
;
503 ASSERT(Type
!= KdbBreakPointNone
);
505 if (Type
== KdbBreakPointHardware
)
507 if ((Address
% Size
) != 0)
509 KdbpPrint("Address (0x%x) must be aligned to a multiple of the size (%d)\n", Address
, Size
);
510 return STATUS_UNSUCCESSFUL
;
512 if (AccessType
== KdbAccessExec
&& Size
!= 1)
514 KdbpPrint("Size must be 1 for execution breakpoints.\n");
515 return STATUS_UNSUCCESSFUL
;
519 if (KdbBreakPointCount
== KDB_MAXIMUM_BREAKPOINT_COUNT
)
521 return STATUS_UNSUCCESSFUL
;
524 /* Parse conditon expression string and duplicate it */
525 if (ConditionExpression
!= NULL
)
527 Condition
= KdbpRpnParseExpression(ConditionExpression
, &ErrOffset
, ErrMsg
);
528 if (Condition
== NULL
)
531 KdbpPrint("Couldn't parse expression: %s at character %d\n", ErrMsg
, ErrOffset
);
533 KdbpPrint("Couldn't parse expression: %s", ErrMsg
);
534 return STATUS_UNSUCCESSFUL
;
537 i
= strlen(ConditionExpression
) + 1;
538 ConditionExpressionDup
= ExAllocatePoolWithTag(NonPagedPool
, i
, TAG_KDBG
);
539 RtlCopyMemory(ConditionExpressionDup
, ConditionExpression
, i
);
545 ConditionExpressionDup
= NULL
;
548 /* Find unused breakpoint */
549 if (Type
== KdbBreakPointTemporary
)
551 for (i
= RTL_NUMBER_OF(KdbBreakPoints
) - 1; i
>= 0; i
--)
553 if (KdbBreakPoints
[i
].Type
== KdbBreakPointNone
)
559 for (i
= 0; i
< RTL_NUMBER_OF(KdbBreakPoints
); i
++)
561 if (KdbBreakPoints
[i
].Type
== KdbBreakPointNone
)
565 ASSERT(i
< RTL_NUMBER_OF(KdbBreakPoints
));
567 /* Set the breakpoint */
568 ASSERT(KdbCurrentProcess
!= NULL
);
569 KdbBreakPoints
[i
].Type
= Type
;
570 KdbBreakPoints
[i
].Address
= Address
;
571 KdbBreakPoints
[i
].Enabled
= FALSE
;
572 KdbBreakPoints
[i
].Global
= Global
;
573 KdbBreakPoints
[i
].Process
= KdbCurrentProcess
;
574 KdbBreakPoints
[i
].ConditionExpression
= ConditionExpressionDup
;
575 KdbBreakPoints
[i
].Condition
= Condition
;
576 if (Type
== KdbBreakPointHardware
)
579 KdbBreakPoints
[i
].Data
.Hw
.Size
= Size
;
580 KdbBreakPoints
[i
].Data
.Hw
.AccessType
= AccessType
;
582 KdbBreakPointCount
++;
584 if (Type
!= KdbBreakPointTemporary
)
585 KdbpPrint("Breakpoint %d inserted.\n", i
);
587 /* Try to enable the breakpoint */
588 KdbpEnableBreakPoint(i
, NULL
);
590 /* Return the breakpoint number */
591 if (BreakPointNumber
!= NULL
)
592 *BreakPointNumber
= i
;
594 return STATUS_SUCCESS
;
597 /*!\brief Deletes a breakpoint
599 * \param BreakPointNr Number of the breakpoint to delete. Can be -1
600 * \param BreakPoint Breakpoint to delete. Can be NULL.
602 * \retval TRUE Success.
603 * \retval FALSE Failure (invalid breakpoint number)
606 KdbpDeleteBreakPoint(
607 IN LONG BreakPointNr OPTIONAL
,
608 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL
)
610 if (BreakPointNr
< 0)
612 ASSERT(BreakPoint
!= NULL
);
613 BreakPointNr
= BreakPoint
- KdbBreakPoints
;
615 if (BreakPointNr
< 0 || BreakPointNr
>= KDB_MAXIMUM_BREAKPOINT_COUNT
)
617 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
620 if (BreakPoint
== NULL
)
622 BreakPoint
= KdbBreakPoints
+ BreakPointNr
;
624 if (BreakPoint
->Type
== KdbBreakPointNone
)
626 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
630 if (BreakPoint
->Enabled
&&
631 !KdbpDisableBreakPoint(-1, BreakPoint
))
634 if (BreakPoint
->Type
!= KdbBreakPointTemporary
)
635 KdbpPrint("Breakpoint %d deleted.\n", BreakPointNr
);
636 BreakPoint
->Type
= KdbBreakPointNone
;
637 KdbBreakPointCount
--;
642 /*!\brief Checks if the breakpoint was set by the debugger
644 * Tries to find a breakpoint in the breakpoint array which caused
645 * the debug exception to happen.
647 * \param ExpNr Exception Number (1 or 3)
648 * \param TrapFrame Exception trapframe
650 * \returns Breakpoint number, -1 on error.
653 KdbpIsBreakPointOurs(
655 IN PKTRAP_FRAME TrapFrame
)
658 ASSERT(ExpNr
== 1 || ExpNr
== 3);
660 if (ExpNr
== 3) /* Software interrupt */
662 ULONG_PTR BpEip
= (ULONG_PTR
)TrapFrame
->Eip
- 1; /* Get EIP of INT3 instruction */
663 for (i
= 0; i
< KdbSwBreakPointCount
; i
++)
665 ASSERT((KdbSwBreakPoints
[i
]->Type
== KdbBreakPointSoftware
||
666 KdbSwBreakPoints
[i
]->Type
== KdbBreakPointTemporary
));
667 ASSERT(KdbSwBreakPoints
[i
]->Enabled
);
668 if (KdbSwBreakPoints
[i
]->Address
== BpEip
)
670 return KdbSwBreakPoints
[i
] - KdbBreakPoints
;
674 else if (ExpNr
== 1) /* Hardware interrupt */
677 for (i
= 0; i
< KdbHwBreakPointCount
; i
++)
679 ASSERT(KdbHwBreakPoints
[i
]->Type
== KdbBreakPointHardware
&&
680 KdbHwBreakPoints
[i
]->Enabled
);
681 DebugReg
= KdbHwBreakPoints
[i
]->Data
.Hw
.DebugReg
;
682 if ((TrapFrame
->Dr6
& (1 << DebugReg
)) != 0)
684 return KdbHwBreakPoints
[i
] - KdbBreakPoints
;
692 /*!\brief Enables a breakpoint.
694 * \param BreakPointNr Number of the breakpoint to enable Can be -1.
695 * \param BreakPoint Breakpoint to enable. Can be NULL.
697 * \retval TRUE Success.
698 * \retval FALSE Failure.
700 * \sa KdbpDisableBreakPoint
703 KdbpEnableBreakPoint(
704 IN LONG BreakPointNr OPTIONAL
,
705 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL
)
711 if (BreakPointNr
< 0)
713 ASSERT(BreakPoint
!= NULL
);
714 BreakPointNr
= BreakPoint
- KdbBreakPoints
;
716 if (BreakPointNr
< 0 || BreakPointNr
>= KDB_MAXIMUM_BREAKPOINT_COUNT
)
718 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
721 if (BreakPoint
== NULL
)
723 BreakPoint
= KdbBreakPoints
+ BreakPointNr
;
725 if (BreakPoint
->Type
== KdbBreakPointNone
)
727 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
731 if (BreakPoint
->Enabled
== TRUE
)
733 KdbpPrint("Breakpoint %d is already enabled.\n", BreakPointNr
);
737 if (BreakPoint
->Type
== KdbBreakPointSoftware
||
738 BreakPoint
->Type
== KdbBreakPointTemporary
)
740 if (KdbSwBreakPointCount
>= KDB_MAXIMUM_SW_BREAKPOINT_COUNT
)
742 KdbpPrint("Maximum number of SW breakpoints (%d) used. "
743 "Disable another breakpoint in order to enable this one.\n",
744 KDB_MAXIMUM_SW_BREAKPOINT_COUNT
);
747 Status
= KdbpOverwriteInstruction(BreakPoint
->Process
, BreakPoint
->Address
,
748 0xCC, &BreakPoint
->Data
.SavedInstruction
);
749 if (!NT_SUCCESS(Status
))
751 KdbpPrint("Couldn't access memory at 0x%x\n", BreakPoint
->Address
);
754 KdbSwBreakPoints
[KdbSwBreakPointCount
++] = BreakPoint
;
758 if (BreakPoint
->Data
.Hw
.AccessType
== KdbAccessExec
)
759 ASSERT(BreakPoint
->Data
.Hw
.Size
== 1);
760 ASSERT((BreakPoint
->Address
% BreakPoint
->Data
.Hw
.Size
) == 0);
761 if (KdbHwBreakPointCount
>= KDB_MAXIMUM_HW_BREAKPOINT_COUNT
)
763 KdbpPrint("Maximum number of HW breakpoints (%d) already used. "
764 "Disable another breakpoint in order to enable this one.\n",
765 KDB_MAXIMUM_HW_BREAKPOINT_COUNT
);
769 /* Find unused hw breakpoint */
770 ASSERT(KDB_MAXIMUM_HW_BREAKPOINT_COUNT
== 4);
771 for (i
= 0; i
< KDB_MAXIMUM_HW_BREAKPOINT_COUNT
; i
++)
773 if ((KdbTrapFrame
.Tf
.Dr7
& (0x3 << (i
* 2))) == 0)
776 ASSERT(i
< KDB_MAXIMUM_HW_BREAKPOINT_COUNT
);
778 /* Set the breakpoint address. */
782 KdbTrapFrame
.Tf
.Dr0
= BreakPoint
->Address
;
785 KdbTrapFrame
.Tf
.Dr1
= BreakPoint
->Address
;
788 KdbTrapFrame
.Tf
.Dr2
= BreakPoint
->Address
;
791 KdbTrapFrame
.Tf
.Dr3
= BreakPoint
->Address
;
795 /* Enable the global breakpoint */
796 KdbTrapFrame
.Tf
.Dr7
|= (0x2 << (i
* 2));
798 /* Enable the exact match bits. */
799 KdbTrapFrame
.Tf
.Dr7
|= 0x00000300;
801 /* Clear existing state. */
802 KdbTrapFrame
.Tf
.Dr7
&= ~(0xF << (16 + (i
* 4)));
804 /* Set the breakpoint type. */
805 switch (BreakPoint
->Data
.Hw
.AccessType
)
814 case KdbAccessReadWrite
:
822 KdbTrapFrame
.Tf
.Dr7
|= (ul
<< (16 + (i
* 4)));
824 /* Set the breakpoint length. */
825 KdbTrapFrame
.Tf
.Dr7
|= ((BreakPoint
->Data
.Hw
.Size
- 1) << (18 + (i
* 4)));
827 /* Update KdbCurrentTrapFrame - values are taken from there by the CLI */
828 if (&KdbTrapFrame
!= KdbCurrentTrapFrame
)
830 KdbCurrentTrapFrame
->Tf
.Dr0
= KdbTrapFrame
.Tf
.Dr0
;
831 KdbCurrentTrapFrame
->Tf
.Dr1
= KdbTrapFrame
.Tf
.Dr1
;
832 KdbCurrentTrapFrame
->Tf
.Dr2
= KdbTrapFrame
.Tf
.Dr2
;
833 KdbCurrentTrapFrame
->Tf
.Dr3
= KdbTrapFrame
.Tf
.Dr3
;
834 KdbCurrentTrapFrame
->Tf
.Dr6
= KdbTrapFrame
.Tf
.Dr6
;
835 KdbCurrentTrapFrame
->Tf
.Dr7
= KdbTrapFrame
.Tf
.Dr7
;
838 BreakPoint
->Data
.Hw
.DebugReg
= i
;
839 KdbHwBreakPoints
[KdbHwBreakPointCount
++] = BreakPoint
;
842 BreakPoint
->Enabled
= TRUE
;
843 if (BreakPoint
->Type
!= KdbBreakPointTemporary
)
844 KdbpPrint("Breakpoint %d enabled.\n", BreakPointNr
);
848 /*!\brief Disables a breakpoint.
850 * \param BreakPointNr Number of the breakpoint to disable. Can be -1
851 * \param BreakPoint Breakpoint to disable. Can be NULL.
853 * \retval TRUE Success.
854 * \retval FALSE Failure.
856 * \sa KdbpEnableBreakPoint
859 KdbpDisableBreakPoint(
860 IN LONG BreakPointNr OPTIONAL
,
861 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL
)
866 if (BreakPointNr
< 0)
868 ASSERT(BreakPoint
!= NULL
);
869 BreakPointNr
= BreakPoint
- KdbBreakPoints
;
871 if (BreakPointNr
< 0 || BreakPointNr
>= KDB_MAXIMUM_BREAKPOINT_COUNT
)
873 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
876 if (BreakPoint
== NULL
)
878 BreakPoint
= KdbBreakPoints
+ BreakPointNr
;
880 if (BreakPoint
->Type
== KdbBreakPointNone
)
882 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr
);
886 if (BreakPoint
->Enabled
== FALSE
)
888 KdbpPrint("Breakpoint %d is not enabled.\n", BreakPointNr
);
892 if (BreakPoint
->Type
== KdbBreakPointSoftware
||
893 BreakPoint
->Type
== KdbBreakPointTemporary
)
895 ASSERT(KdbSwBreakPointCount
> 0);
896 Status
= KdbpOverwriteInstruction(BreakPoint
->Process
, BreakPoint
->Address
,
897 BreakPoint
->Data
.SavedInstruction
, NULL
);
898 if (!NT_SUCCESS(Status
))
900 KdbpPrint("Couldn't restore original instruction.\n");
904 for (i
= 0; i
< KdbSwBreakPointCount
; i
++)
906 if (KdbSwBreakPoints
[i
] == BreakPoint
)
908 KdbSwBreakPoints
[i
] = KdbSwBreakPoints
[--KdbSwBreakPointCount
];
909 i
= -1; /* if the last breakpoint is disabled dont break with i >= KdbSwBreakPointCount */
913 if (i
!= -1) /* not found */
918 ASSERT(BreakPoint
->Type
== KdbBreakPointHardware
);
920 /* Clear the breakpoint. */
921 KdbTrapFrame
.Tf
.Dr7
&= ~(0x3 << (BreakPoint
->Data
.Hw
.DebugReg
* 2));
922 if ((KdbTrapFrame
.Tf
.Dr7
& 0xFF) == 0)
925 * If no breakpoints are enabled then clear the exact match flags.
927 KdbTrapFrame
.Tf
.Dr7
&= 0xFFFFFCFF;
930 for (i
= 0; i
< KdbHwBreakPointCount
; i
++)
932 if (KdbHwBreakPoints
[i
] == BreakPoint
)
934 KdbHwBreakPoints
[i
] = KdbHwBreakPoints
[--KdbHwBreakPointCount
];
935 i
= -1; /* if the last breakpoint is disabled dont break with i >= KdbHwBreakPointCount */
939 if (i
!= -1) /* not found */
943 BreakPoint
->Enabled
= FALSE
;
944 if (BreakPoint
->Type
!= KdbBreakPointTemporary
)
945 KdbpPrint("Breakpoint %d disabled.\n", BreakPointNr
);
949 /*!\brief Gets the first or last chance enter-condition for exception nr. \a ExceptionNr
951 * \param ExceptionNr Number of the exception to get condition of.
952 * \param FirstChance Whether to get first or last chance condition.
953 * \param Condition Receives the condition setting.
955 * \retval TRUE Success.
956 * \retval FALSE Failure (invalid exception nr)
959 KdbpGetEnterCondition(
961 IN BOOLEAN FirstChance
,
962 OUT KDB_ENTER_CONDITION
*Condition
)
964 if (ExceptionNr
>= RTL_NUMBER_OF(KdbEnterConditions
))
967 *Condition
= KdbEnterConditions
[ExceptionNr
][FirstChance
? 0 : 1];
971 /*!\brief Sets the first or last chance enter-condition for exception nr. \a ExceptionNr
973 * \param ExceptionNr Number of the exception to set condition of (-1 for all)
974 * \param FirstChance Whether to set first or last chance condition.
975 * \param Condition The new condition setting.
977 * \retval TRUE Success.
978 * \retval FALSE Failure (invalid exception nr)
981 KdbpSetEnterCondition(
983 IN BOOLEAN FirstChance
,
984 IN KDB_ENTER_CONDITION Condition
)
988 for (ExceptionNr
= 0; ExceptionNr
< RTL_NUMBER_OF(KdbEnterConditions
); ExceptionNr
++)
990 if (ExceptionNr
== 1 || ExceptionNr
== 8 ||
991 ExceptionNr
== 9 || ExceptionNr
== 15) /* Reserved exceptions */
995 KdbEnterConditions
[ExceptionNr
][FirstChance
? 0 : 1] = Condition
;
1000 if (ExceptionNr
>= RTL_NUMBER_OF(KdbEnterConditions
) ||
1001 ExceptionNr
== 1 || ExceptionNr
== 8 || /* Do not allow changing of the debug */
1002 ExceptionNr
== 9 || ExceptionNr
== 15) /* trap or reserved exceptions */
1006 KdbEnterConditions
[ExceptionNr
][FirstChance
? 0 : 1] = Condition
;
1011 /*!\brief Switches to another thread context
1013 * \param ThreadId Id of the thread to switch to.
1015 * \retval TRUE Success.
1016 * \retval FALSE Failure (i.e. invalid thread id)
1022 PETHREAD Thread
= NULL
;
1025 /* Get a pointer to the thread */
1026 if (!NT_SUCCESS(PsLookupThreadByThreadId(ThreadId
, &Thread
)))
1028 KdbpPrint("Invalid thread id: 0x%08x\n", (UINT
)ThreadId
);
1031 Process
= Thread
->ThreadsProcess
;
1033 if (KeIsExecutingDpc() && Process
!= KdbCurrentProcess
)
1035 KdbpPrint("Cannot attach to thread within another process while executing a DPC.\n");
1039 /* Save the current thread's context (if we previously attached to a thread) */
1040 if (KdbCurrentThread
!= KdbOriginalThread
)
1042 ASSERT(KdbCurrentTrapFrame
== &KdbThreadTrapFrame
);
1043 KdbpKdbTrapFrameToTrapFrame(KdbCurrentTrapFrame
, KdbCurrentThread
->Tcb
.TrapFrame
);
1047 ASSERT(KdbCurrentTrapFrame
== &KdbTrapFrame
);
1050 /* Switch to the thread's context */
1051 if (Thread
!= KdbOriginalThread
)
1053 if (Thread
->Tcb
.TrapFrame
== NULL
)
1055 KdbpPrint("Threads TrapFrame is NULL! Cannot attach.\n");
1058 KdbpTrapFrameToKdbTrapFrame(Thread
->Tcb
.TrapFrame
, &KdbThreadTrapFrame
);
1059 KdbCurrentTrapFrame
= &KdbThreadTrapFrame
;
1061 else /* Switching back to original thread */
1063 KdbCurrentTrapFrame
= &KdbTrapFrame
;
1065 KdbCurrentThread
= Thread
;
1067 /* Attach to the thread's process */
1068 ASSERT(KdbCurrentProcess
== PsGetCurrentProcess());
1069 if (KdbCurrentProcess
!= Process
)
1071 if (KdbCurrentProcess
!= KdbOriginalProcess
) /* detach from previously attached process */
1073 KeUnstackDetachProcess(&KdbApcState
);
1075 if (KdbOriginalProcess
!= Process
)
1077 KeStackAttachProcess(EPROCESS_TO_KPROCESS(Process
), &KdbApcState
);
1079 KdbCurrentProcess
= Process
;
1085 /*!\brief Switches to another process/thread context
1087 * This function switches to the first thread in the specified process.
1089 * \param ProcessId Id of the process to switch to.
1091 * \retval TRUE Success.
1092 * \retval FALSE Failure (i.e. invalid process id)
1095 KdbpAttachToProcess(
1098 PEPROCESS Process
= NULL
;
1102 /* Get a pointer to the process */
1103 if (!NT_SUCCESS(PsLookupProcessByProcessId(ProcessId
, &Process
)))
1105 KdbpPrint("Invalid process id: 0x%08x\n", (UINT
)ProcessId
);
1109 Entry
= Process
->ThreadListHead
.Flink
;
1110 if (Entry
== &KdbCurrentProcess
->ThreadListHead
)
1112 KdbpPrint("No threads in process 0x%08x, cannot attach to process!\n", (UINT
)ProcessId
);
1116 Thread
= CONTAINING_RECORD(Entry
, ETHREAD
, ThreadListEntry
);
1118 return KdbpAttachToThread(Thread
->Cid
.UniqueThread
);
1121 /*!\brief Calls the main loop ...
1126 KdbpCliMainLoop(KdbEnteredOnSingleStep
);
1129 /*!\brief Internal function to enter KDB.
1131 * Disables interrupts, releases display ownership, ...
1137 PVOID SavedInitialStack
, SavedStackBase
, SavedKernelStack
;
1138 ULONG SavedStackLimit
;
1141 if (KdpDebugMode
.Screen
)
1143 HalReleaseDisplayOwnership();
1146 /* Call the interface's main loop on a different stack */
1147 Thread
= PsGetCurrentThread();
1148 SavedInitialStack
= Thread
->Tcb
.InitialStack
;
1149 SavedStackBase
= Thread
->Tcb
.StackBase
;
1150 SavedStackLimit
= Thread
->Tcb
.StackLimit
;
1151 SavedKernelStack
= Thread
->Tcb
.KernelStack
;
1152 Thread
->Tcb
.InitialStack
= Thread
->Tcb
.StackBase
= (char*)KdbStack
+ KDB_STACK_SIZE
;
1153 Thread
->Tcb
.StackLimit
= (ULONG
)KdbStack
;
1154 Thread
->Tcb
.KernelStack
= (char*)KdbStack
+ KDB_STACK_SIZE
;
1156 /*KdbpPrint("Switching to KDB stack 0x%08x-0x%08x\n", Thread->Tcb.StackLimit, Thread->Tcb.StackBase);*/
1158 KdbpStackSwitchAndCall(Thread
->Tcb
.KernelStack
, KdbpCallMainLoop
);
1160 Thread
->Tcb
.InitialStack
= SavedInitialStack
;
1161 Thread
->Tcb
.StackBase
= SavedStackBase
;
1162 Thread
->Tcb
.StackLimit
= SavedStackLimit
;
1163 Thread
->Tcb
.KernelStack
= SavedKernelStack
;
1167 /*!\brief KDB Exception filter
1169 * Called by the exception dispatcher.
1171 * \param ExceptionRecord Unused.
1172 * \param PreviousMode UserMode if the exception was raised from umode, otherwise KernelMode.
1173 * \param Context Unused.
1174 * \param TrapFrame Exception TrapFrame.
1175 * \param FirstChance TRUE when called before exception frames were serached,
1176 * FALSE for the second call.
1178 * \returns KD_CONTINUE_TYPE
1181 KdbEnterDebuggerException(
1182 IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL
,
1183 IN KPROCESSOR_MODE PreviousMode
,
1184 IN PCONTEXT Context OPTIONAL
,
1185 IN OUT PKTRAP_FRAME TrapFrame
,
1186 IN BOOLEAN FirstChance
)
1188 ULONG ExpNr
= (ULONG
)TrapFrame
->DebugArgMark
;
1189 KDB_ENTER_CONDITION EnterCondition
;
1190 KD_CONTINUE_TYPE ContinueType
= kdHandleException
;
1191 PKDB_BREAKPOINT BreakPoint
;
1194 BOOLEAN Resume
= FALSE
;
1195 BOOLEAN EnterConditionMet
= TRUE
;
1198 KdbCurrentProcess
= PsGetCurrentProcess();
1200 /* Set continue type to kdContinue for single steps and breakpoints */
1201 if (ExpNr
== 1 || ExpNr
== 3)
1202 ContinueType
= kdContinue
;
1204 /* Check if we should handle the exception. */
1205 ul
= min(ExpNr
, RTL_NUMBER_OF(KdbEnterConditions
) - 1);
1206 EnterCondition
= KdbEnterConditions
[ul
][FirstChance
? 0 : 1];
1207 if (EnterCondition
== KdbDoNotEnter
||
1208 (EnterCondition
== KdbEnterFromUmode
&& PreviousMode
!= UserMode
) ||
1209 (EnterCondition
== KdbEnterFromKmode
&& PreviousMode
!= KernelMode
))
1211 EnterConditionMet
= FALSE
;
1214 /* If we stopped on one of our breakpoints then let the user know. */
1215 KdbLastBreakPointNr
= -1;
1216 KdbEnteredOnSingleStep
= FALSE
;
1218 if (FirstChance
&& (ExpNr
== 1 || ExpNr
== 3) &&
1219 (KdbLastBreakPointNr
= KdbpIsBreakPointOurs(ExpNr
, TrapFrame
)) >= 0)
1221 BreakPoint
= KdbBreakPoints
+ KdbLastBreakPointNr
;
1226 * The breakpoint will point to the next instruction by default so
1227 * point it back to the start of original instruction.
1232 * ... and restore the original instruction.
1234 if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess
, BreakPoint
->Address
,
1235 BreakPoint
->Data
.SavedInstruction
, NULL
)))
1237 DbgPrint("Couldn't restore original instruction after INT3! Cannot continue execution.\n");
1242 if ((BreakPoint
->Type
== KdbBreakPointHardware
) &&
1243 (BreakPoint
->Data
.Hw
.AccessType
== KdbAccessExec
))
1245 Resume
= TRUE
; /* Set the resume flag when continuing execution */
1249 * When a temporary breakpoint is hit we have to make sure that we are
1250 * in the same context in which it was set, otherwise it could happen
1251 * that another process/thread hits it before and it gets deleted.
1253 else if (BreakPoint
->Type
== KdbBreakPointTemporary
&&
1254 BreakPoint
->Process
== KdbCurrentProcess
)
1256 ASSERT((TrapFrame
->Eflags
& X86_EFLAGS_TF
) == 0);
1259 * Delete the temporary breakpoint which was used to step over or into the instruction.
1261 KdbpDeleteBreakPoint(-1, BreakPoint
);
1263 if (--KdbNumSingleSteps
> 0)
1265 if ((KdbSingleStepOver
&& !KdbpStepOverInstruction(TrapFrame
->Eip
)) ||
1266 (!KdbSingleStepOver
&& !KdbpStepIntoInstruction(TrapFrame
->Eip
)))
1268 TrapFrame
->Eflags
|= X86_EFLAGS_TF
;
1270 goto continue_execution
; /* return */
1273 KdbEnteredOnSingleStep
= TRUE
;
1277 * If we hit a breakpoint set by the debugger we set the single step flag,
1278 * ignore the next single step and reenable the breakpoint.
1280 else if (BreakPoint
->Type
== KdbBreakPointSoftware
||
1281 BreakPoint
->Type
== KdbBreakPointTemporary
)
1284 TrapFrame
->Eflags
|= X86_EFLAGS_TF
;
1285 KdbBreakPointToReenable
= BreakPoint
;
1289 * Make sure that the breakpoint should be triggered in this context
1291 if (!BreakPoint
->Global
&& BreakPoint
->Process
!= KdbCurrentProcess
)
1293 goto continue_execution
; /* return */
1297 * Check if the condition for the breakpoint is met.
1299 if (BreakPoint
->Condition
!= NULL
)
1301 /* Setup the KDB trap frame */
1302 KdbpTrapFrameToKdbTrapFrame(TrapFrame
, &KdbTrapFrame
);
1305 if (!KdbpRpnEvaluateParsedExpression(BreakPoint
->Condition
, &KdbTrapFrame
, &ull
, NULL
, NULL
))
1307 /* FIXME: Print warning? */
1309 else if (ull
== 0) /* condition is not met */
1311 goto continue_execution
; /* return */
1315 if (BreakPoint
->Type
== KdbBreakPointSoftware
)
1317 DbgPrint("Entered debugger on breakpoint #%d: EXEC 0x%04x:0x%08x\n",
1318 KdbLastBreakPointNr
, TrapFrame
->Cs
& 0xffff, TrapFrame
->Eip
);
1320 else if (BreakPoint
->Type
== KdbBreakPointHardware
)
1322 DbgPrint("Entered debugger on breakpoint #%d: %s 0x%08x\n",
1323 KdbLastBreakPointNr
,
1324 (BreakPoint
->Data
.Hw
.AccessType
== KdbAccessRead
) ? "READ" :
1325 ((BreakPoint
->Data
.Hw
.AccessType
== KdbAccessWrite
) ? "WRITE" :
1326 ((BreakPoint
->Data
.Hw
.AccessType
== KdbAccessReadWrite
) ? "RDWR" : "EXEC")
1333 else if (ExpNr
== 1)
1335 /* Silently ignore a debugger initiated single step. */
1336 if ((TrapFrame
->Dr6
& 0xf) == 0 && KdbBreakPointToReenable
!= NULL
)
1338 /* FIXME: Make sure that the breakpoint was really hit (check bp->Address vs. tf->Eip) */
1339 BreakPoint
= KdbBreakPointToReenable
;
1340 KdbBreakPointToReenable
= NULL
;
1341 ASSERT(BreakPoint
->Type
== KdbBreakPointSoftware
||
1342 BreakPoint
->Type
== KdbBreakPointTemporary
);
1345 * Reenable the breakpoint we disabled to execute the breakpointed
1348 if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess
, BreakPoint
->Address
, 0xCC,
1349 &BreakPoint
->Data
.SavedInstruction
)))
1351 DbgPrint("Warning: Couldn't reenable breakpoint %d\n",
1352 BreakPoint
- KdbBreakPoints
);
1355 /* Unset TF if we are no longer single stepping. */
1356 if (KdbNumSingleSteps
== 0)
1357 TrapFrame
->Eflags
&= ~X86_EFLAGS_TF
;
1358 goto continue_execution
; /* return */
1361 /* Check if we expect a single step */
1362 if ((TrapFrame
->Dr6
& 0xf) == 0 && KdbNumSingleSteps
> 0)
1364 /*ASSERT((TrapFrame->Eflags & X86_EFLAGS_TF) != 0);*/
1365 if (--KdbNumSingleSteps
> 0)
1367 if ((KdbSingleStepOver
&& KdbpStepOverInstruction(TrapFrame
->Eip
)) ||
1368 (!KdbSingleStepOver
&& KdbpStepIntoInstruction(TrapFrame
->Eip
)))
1370 TrapFrame
->Eflags
&= ~X86_EFLAGS_TF
;
1374 TrapFrame
->Eflags
|= X86_EFLAGS_TF
;
1376 goto continue_execution
; /* return */
1379 TrapFrame
->Eflags
&= ~X86_EFLAGS_TF
;
1380 KdbEnteredOnSingleStep
= TRUE
;
1384 if (!EnterConditionMet
)
1386 return ContinueType
;
1388 DbgPrint("Entered debugger on unexpected debug trap!\n");
1391 else if (ExpNr
== 3)
1393 if (KdbInitFileBuffer
!= NULL
)
1395 KdbpCliInterpretInitFile();
1396 EnterConditionMet
= FALSE
;
1398 if (!EnterConditionMet
)
1400 return ContinueType
;
1403 DbgPrint("Entered debugger on embedded INT3 at 0x%04x:0x%08x.\n",
1404 TrapFrame
->Cs
& 0xffff, TrapFrame
->Eip
- 1);
1408 CONST PCHAR ExceptionString
= (ExpNr
< RTL_NUMBER_OF(ExceptionNrToString
)) ?
1409 (ExceptionNrToString
[ExpNr
]) :
1410 ("Unknown/User defined exception");
1412 if (!EnterConditionMet
)
1414 return ContinueType
;
1417 DbgPrint("Entered debugger on %s-chance exception number %d (%s)\n",
1418 FirstChance
? "first" : "last", ExpNr
, ExceptionString
);
1421 /* FIXME: Add noexec memory stuff */
1423 asm volatile("movl %%cr2, %0" : "=r"(Cr2
));
1424 Err
= TrapFrame
->ErrorCode
;
1425 DbgPrint("Memory at 0x%x could not be %s: ", Cr2
, (Err
& (1 << 1)) ? "written" : "read");
1426 if ((Err
& (1 << 0)) == 0)
1427 DbgPrint("Page not present.\n");
1430 if ((Err
& (1 << 3)) != 0)
1431 DbgPrint("Reserved bits in page directory set.\n");
1433 DbgPrint("Page protection violation.\n");
1438 /* Once we enter the debugger we do not expect any more single steps to happen */
1439 KdbNumSingleSteps
= 0;
1441 /* Update the current process pointer */
1442 KdbCurrentProcess
= KdbOriginalProcess
= PsGetCurrentProcess();
1443 KdbCurrentThread
= KdbOriginalThread
= PsGetCurrentThread();
1444 KdbCurrentTrapFrame
= &KdbTrapFrame
;
1446 /* Setup the KDB trap frame */
1447 KdbpTrapFrameToKdbTrapFrame(TrapFrame
, &KdbTrapFrame
);
1449 /* Enter critical section */
1450 Ke386SaveFlags(OldEflags
);
1451 Ke386DisableInterrupts();
1453 /* Exception inside the debugger? Game over. */
1454 if (InterlockedIncrement(&KdbEntryCount
) > 1)
1456 Ke386RestoreFlags(OldEflags
);
1457 return kdHandleException
;
1460 /* Call the main loop. */
1461 KdbpInternalEnter();
1463 /* Check if we should single step */
1464 if (KdbNumSingleSteps
> 0)
1466 if ((KdbSingleStepOver
&& KdbpStepOverInstruction(KdbCurrentTrapFrame
->Tf
.Eip
)) ||
1467 (!KdbSingleStepOver
&& KdbpStepIntoInstruction(KdbCurrentTrapFrame
->Tf
.Eip
)))
1469 ASSERT((KdbCurrentTrapFrame
->Tf
.Eflags
& X86_EFLAGS_TF
) == 0);
1470 /*KdbCurrentTrapFrame->Tf.Eflags &= ~X86_EFLAGS_TF;*/
1474 KdbCurrentTrapFrame
->Tf
.Eflags
|= X86_EFLAGS_TF
;
1478 /* Save the current thread's trapframe */
1479 if (KdbCurrentTrapFrame
== &KdbThreadTrapFrame
)
1481 KdbpKdbTrapFrameToTrapFrame(KdbCurrentTrapFrame
, KdbCurrentThread
->Tcb
.TrapFrame
);
1484 /* Detach from attached process */
1485 if (KdbCurrentProcess
!= KdbOriginalProcess
)
1487 KeUnstackDetachProcess(&KdbApcState
);
1490 /* Update the exception TrapFrame */
1491 KdbpKdbTrapFrameToTrapFrame(&KdbTrapFrame
, TrapFrame
);
1493 /* Decrement the entry count */
1494 InterlockedDecrement(&KdbEntryCount
);
1496 /* Leave critical section */
1497 Ke386RestoreFlags(OldEflags
);
1500 /* Clear debug status */
1501 if (ExpNr
== 1 || ExpNr
== 3) /* FIXME: Why clear DR6 on INT3? */
1503 /* Set the RF flag so we don't trigger the same breakpoint again. */
1506 TrapFrame
->Eflags
|= X86_EFLAGS_RF
;
1509 /* Clear dr6 status flags. */
1510 TrapFrame
->Dr6
&= ~0x0000e00f;
1514 return ContinueType
;
1518 KdbDeleteProcessHook(IN PEPROCESS Process
)
1520 KdbSymFreeProcessSymbols(Process
);
1522 /* FIXME: Delete breakpoints for process */
1527 KdbpGetCommandLineSettings(PCHAR p1
)
1531 while (p1
&& (p2
= strchr(p1
, '/')))
1535 if (!_strnicmp(p2
, "KDSERIAL", 8))
1538 KdbDebugState
|= KD_DEBUG_KDSERIAL
;
1539 KdpDebugMode
.Serial
= TRUE
;
1541 else if (!_strnicmp(p2
, "KDNOECHO", 8))
1544 KdbDebugState
|= KD_DEBUG_KDNOECHO
;