- KdDebuggerNotPresent should be FALSE by default.
[reactos.git] / reactos / ntoskrnl / kd64 / kdtrap.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/kd64/kdtrap.c
5 * PURPOSE: KD64 Trap Handlers
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* FUNCTIONS *****************************************************************/
16
17 BOOLEAN
18 NTAPI
19 KdpReport(IN PKTRAP_FRAME TrapFrame,
20 IN PKEXCEPTION_FRAME ExceptionFrame,
21 IN PEXCEPTION_RECORD ExceptionRecord,
22 IN PCONTEXT ContextRecord,
23 IN KPROCESSOR_MODE PreviousMode,
24 IN BOOLEAN SecondChanceException)
25 {
26 BOOLEAN Entered, Status;
27 PKPRCB Prcb;
28 while (TRUE);
29
30 /*
31 * Only go ahead with this if this is an INT3 or an INT1, or if the global
32 * flag forces us to call up the debugger on exception, or if this is a
33 * second chance exception which means it hasn't been handled by now.
34 */
35 if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) ||
36 (ExceptionRecord->ExceptionCode == STATUS_SINGLE_STEP) ||
37 (NtGlobalFlag & FLG_STOP_ON_EXCEPTION) ||
38 (SecondChanceException))
39 {
40 /*
41 * Also, unless this is a second chance exception, then do not call up
42 * the debugger if the debug port is disconnected or the exception code
43 * indicates success.
44 */
45 if (!(SecondChanceException) &&
46 ((ExceptionRecord->ExceptionCode == STATUS_PORT_DISCONNECTED) ||
47 (NT_SUCCESS(ExceptionRecord->ExceptionCode))))
48 {
49 /* Return false to hide the exception */
50 return FALSE;
51 }
52
53 /* Enter the debugger */
54 Entered = KdEnterDebugger(TrapFrame, ExceptionFrame);
55
56 /*
57 * Get the KPRCB and save the CPU Control State manually instead of
58 * using KiSaveProcessorState, since we already have a valid CONTEXT.
59 */
60 Prcb = KeGetCurrentPrcb();
61 KiSaveProcessorControlState(&Prcb->ProcessorState);
62 RtlCopyMemory(&Prcb->ProcessorState.ContextFrame,
63 ContextRecord,
64 sizeof(CONTEXT));
65
66 /* Report the new state */
67 #if 0
68 Status = KdpReportExceptionStateChange(ExceptionRecord,
69 &Prcb->ProcessorState.
70 ContextFrame,
71 SecondChanceException);
72 #else
73 Status = FALSE;
74 #endif
75
76 /* Now restore the processor state, manually again. */
77 RtlCopyMemory(ContextRecord,
78 &Prcb->ProcessorState.ContextFrame,
79 sizeof(CONTEXT));
80 KiRestoreProcessorControlState(&Prcb->ProcessorState);
81
82 /* Exit the debugger and clear the CTRL-C state */
83 KdExitDebugger(Entered);
84 KdpControlCPressed = FALSE;
85 return Status;
86 }
87
88 /* Fail if we got here */
89 return FALSE;
90 }
91
92 BOOLEAN
93 NTAPI
94 KdpTrap(IN PKTRAP_FRAME TrapFrame,
95 IN PKEXCEPTION_FRAME ExceptionFrame,
96 IN PEXCEPTION_RECORD ExceptionRecord,
97 IN PCONTEXT ContextRecord,
98 IN KPROCESSOR_MODE PreviousMode,
99 IN BOOLEAN SecondChanceException)
100 {
101 BOOLEAN Unload = FALSE;
102 ULONG Eip, Eax;
103 BOOLEAN Status = FALSE;
104
105 /*
106 * Check if we got a STATUS_BREAKPOINT with a SubID for Print, Prompt or
107 * Load/Unload symbols.
108 */
109 if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) &&
110 (ExceptionRecord->ExceptionInformation[0] != BREAKPOINT_BREAK))
111 {
112 /* Save EIP */
113 Eip = ContextRecord->Eip;
114
115 /* Check what kind of operation was requested from us */
116 switch (ExceptionRecord->ExceptionInformation[0])
117 {
118 /* DbgPrint */
119 case BREAKPOINT_PRINT:
120
121 /* Call the worker routine */
122 Eax = KdpPrint(ContextRecord->Ebx,
123 ContextRecord->Edi,
124 (LPSTR)ExceptionRecord->ExceptionInformation[1],
125 (ULONG)ExceptionRecord->ExceptionInformation[2],
126 PreviousMode,
127 TrapFrame,
128 ExceptionFrame,
129 &Status);
130
131 /* Update the return value for the caller */
132 ContextRecord->Eax = Eax;
133 break;
134
135 /* DbgPrompt */
136 case BREAKPOINT_PROMPT:
137
138 /* Call the worker routine */
139 while (TRUE);
140 Eax = 0;
141 Status = TRUE;
142
143 /* Update the return value for the caller */
144 ContextRecord->Eax = Eax;
145 break;
146
147 /* DbgUnloadSymbols */
148 case BREAKPOINT_UNLOAD_SYMBOLS:
149
150 /* Drop into the load case below, with the unload parameter */
151 Unload = TRUE;
152
153 /* DbgLoadSymbols */
154 case BREAKPOINT_LOAD_SYMBOLS:
155
156 /* Call the worker routine */
157 KdpSymbol(UlongToPtr(ExceptionRecord->ExceptionInformation[1]),
158 (ULONG)ExceptionRecord->ExceptionInformation[2],
159 Unload,
160 PreviousMode,
161 ContextRecord,
162 TrapFrame,
163 ExceptionFrame);
164 Status = TRUE;
165 break;
166
167 /* DbgCommandString*/
168 case BREAKPOINT_COMMAND_STRING:
169
170 /* Call the worker routine */
171 while (TRUE);
172 Status = TRUE;
173
174 /* Anything else, do nothing */
175 default:
176
177 /* Get out */
178 break;
179 }
180
181 /*
182 * If EIP was not updated, we'll increment it ourselves so execution
183 * continues past the breakpoint.
184 */
185 if (ContextRecord->Eip == Eip) ContextRecord->Eip++;
186 }
187 else
188 {
189 /* Call the worker routine */
190 Status = KdpReport(TrapFrame,
191 ExceptionFrame,
192 ExceptionRecord,
193 ContextRecord,
194 PreviousMode,
195 SecondChanceException);
196 }
197
198 /* Return TRUE or FALSE to caller */
199 return Status;
200 }
201
202 BOOLEAN
203 NTAPI
204 KdpStub(IN PKTRAP_FRAME TrapFrame,
205 IN PKEXCEPTION_FRAME ExceptionFrame,
206 IN PEXCEPTION_RECORD ExceptionRecord,
207 IN PCONTEXT ContextRecord,
208 IN KPROCESSOR_MODE PreviousMode,
209 IN BOOLEAN SecondChanceException)
210 {
211 ULONG ExceptionCommand = ExceptionRecord->ExceptionInformation[0];
212
213 /* Check if this was a breakpoint due to DbgPrint or Load/UnloadSymbols */
214 if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) &&
215 (ExceptionRecord->NumberParameters > 0) &&
216 ((ExceptionCommand == BREAKPOINT_LOAD_SYMBOLS) ||
217 (ExceptionCommand == BREAKPOINT_UNLOAD_SYMBOLS) ||
218 (ExceptionCommand == BREAKPOINT_COMMAND_STRING) ||
219 (ExceptionCommand == BREAKPOINT_PRINT)))
220 {
221 /* This we can handle: simply bump EIP */
222 ContextRecord->Eip++;
223 return TRUE;
224 }
225 else if (KdPitchDebugger)
226 {
227 /* There's no debugger, fail. */
228 return FALSE;
229 }
230 else if ((KdAutoEnableOnEvent) &&
231 (KdPreviouslyEnabled) &&
232 !(KdDebuggerEnabled) &&
233 (KdEnableDebugger()) &&
234 (KdDebuggerEnabled))
235 {
236 /* Debugging was Auto-Enabled. We can now send this to KD. */
237 return KdpTrap(TrapFrame,
238 ExceptionFrame,
239 ExceptionRecord,
240 ContextRecord,
241 PreviousMode,
242 SecondChanceException);
243 }
244 else
245 {
246 /* FIXME: All we can do in this case is trace this exception */
247 return FALSE;
248 }
249 }