[KD64]
[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 //
16 // Retrieves the ComponentId and Level for BREAKPOINT_PRINT
17 // and OutputString and OutputStringLength for BREAKPOINT_PROMPT.
18 //
19 #if defined(_M_IX86)
20
21 //
22 // EBX/EDI on x86
23 //
24 #define KdpGetFirstParameter(Context) ((Context)->Ebx)
25 #define KdpGetSecondParameter(Context) ((Context)->Edi)
26
27 #elif defined(_M_AMD64)
28
29 //
30 // R8/R9 on AMD64
31 //
32 #define KdpGetFirstParameter(Context) ((Context)->R8)
33 #define KdpGetSecondParameter(Context) ((Context)->R9)
34
35 #elif defined(_M_ARM)
36
37 #error Yo Ninjas!
38
39 #else
40 #error Unsupported Architecture
41 #endif
42
43 /* FUNCTIONS *****************************************************************/
44
45 BOOLEAN
46 NTAPI
47 KdpReport(IN PKTRAP_FRAME TrapFrame,
48 IN PKEXCEPTION_FRAME ExceptionFrame,
49 IN PEXCEPTION_RECORD ExceptionRecord,
50 IN PCONTEXT ContextRecord,
51 IN KPROCESSOR_MODE PreviousMode,
52 IN BOOLEAN SecondChanceException)
53 {
54 BOOLEAN Entered, Status;
55 PKPRCB Prcb;
56 NTSTATUS ExceptionCode = ExceptionRecord->ExceptionCode;
57
58 /* Check if this is single step or a breakpoint, or if we're forced to handle it */
59 if ((ExceptionCode == STATUS_BREAKPOINT) ||
60 (ExceptionCode == STATUS_SINGLE_STEP) ||
61 (ExceptionCode == STATUS_ASSERTION_FAILURE) ||
62 (NtGlobalFlag & FLG_STOP_ON_EXCEPTION))
63 {
64 /* Check if we can't really handle this */
65 if ((SecondChanceException) ||
66 (ExceptionCode == STATUS_PORT_DISCONNECTED) ||
67 (NT_SUCCESS(ExceptionCode)))
68 {
69 /* Return false to have someone else take care of the exception */
70 return FALSE;
71 }
72 }
73 else if (SecondChanceException)
74 {
75 /* We won't bother unless this is first chance */
76 return FALSE;
77 }
78
79 /* Enter the debugger */
80 Entered = KdEnterDebugger(TrapFrame, ExceptionFrame);
81
82 /*
83 * Get the KPRCB and save the CPU Control State manually instead of
84 * using KiSaveProcessorState, since we already have a valid CONTEXT.
85 */
86 Prcb = KeGetCurrentPrcb();
87 KiSaveProcessorControlState(&Prcb->ProcessorState);
88 RtlCopyMemory(&Prcb->ProcessorState.ContextFrame,
89 ContextRecord,
90 sizeof(CONTEXT));
91
92 /* Report the new state */
93 Status = KdpReportExceptionStateChange(ExceptionRecord,
94 &Prcb->ProcessorState.
95 ContextFrame,
96 SecondChanceException);
97
98 /* Now restore the processor state, manually again. */
99 RtlCopyMemory(ContextRecord,
100 &Prcb->ProcessorState.ContextFrame,
101 sizeof(CONTEXT));
102 KiRestoreProcessorControlState(&Prcb->ProcessorState);
103
104 /* Exit the debugger and clear the CTRL-C state */
105 KdExitDebugger(Entered);
106 KdpControlCPressed = FALSE;
107 return Status;
108 }
109
110 BOOLEAN
111 NTAPI
112 KdpTrap(IN PKTRAP_FRAME TrapFrame,
113 IN PKEXCEPTION_FRAME ExceptionFrame,
114 IN PEXCEPTION_RECORD ExceptionRecord,
115 IN PCONTEXT ContextRecord,
116 IN KPROCESSOR_MODE PreviousMode,
117 IN BOOLEAN SecondChanceException)
118 {
119 BOOLEAN Unload = FALSE;
120 ULONG_PTR ProgramCounter, ReturnValue;
121 BOOLEAN Status = FALSE;
122
123 /*
124 * Check if we got a STATUS_BREAKPOINT with a SubID for Print, Prompt or
125 * Load/Unload symbols.
126 */
127 if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) &&
128 (ExceptionRecord->ExceptionInformation[0] != BREAKPOINT_BREAK))
129 {
130 /* Save Program Counter */
131 ProgramCounter = KeGetContextPc(ContextRecord);
132
133 /* Check what kind of operation was requested from us */
134 switch (ExceptionRecord->ExceptionInformation[0])
135 {
136 /* DbgPrint */
137 case BREAKPOINT_PRINT:
138
139 /* Call the worker routine */
140 ReturnValue = KdpPrint((ULONG)KdpGetFirstParameter(ContextRecord),
141 (ULONG)KdpGetSecondParameter(ContextRecord),
142 (LPSTR)ExceptionRecord->
143 ExceptionInformation[1],
144 (USHORT)ExceptionRecord->
145 ExceptionInformation[2],
146 PreviousMode,
147 TrapFrame,
148 ExceptionFrame,
149 &Status);
150
151 /* Update the return value for the caller */
152 KeSetContextReturnRegister(ContextRecord, ReturnValue);
153 break;
154
155 /* DbgPrompt */
156 case BREAKPOINT_PROMPT:
157
158 /* Call the worker routine */
159 ReturnValue = KdpPrompt((LPSTR)ExceptionRecord->
160 ExceptionInformation[1],
161 (USHORT)ExceptionRecord->
162 ExceptionInformation[2],
163 (LPSTR)KdpGetFirstParameter(ContextRecord),
164 (USHORT)KdpGetSecondParameter(ContextRecord),
165 PreviousMode,
166 TrapFrame,
167 ExceptionFrame);
168 Status = TRUE;
169
170 /* Update the return value for the caller */
171 KeSetContextReturnRegister(ContextRecord, ReturnValue);
172 break;
173
174 /* DbgUnLoadImageSymbols */
175 case BREAKPOINT_UNLOAD_SYMBOLS:
176
177 /* Drop into the load case below, with the unload parameter */
178 Unload = TRUE;
179
180 /* DbgLoadImageSymbols */
181 case BREAKPOINT_LOAD_SYMBOLS:
182
183 /* Call the worker routine */
184 KdpSymbol((PSTRING)ExceptionRecord->
185 ExceptionInformation[1],
186 (PKD_SYMBOLS_INFO)ExceptionRecord->
187 ExceptionInformation[2],
188 Unload,
189 PreviousMode,
190 ContextRecord,
191 TrapFrame,
192 ExceptionFrame);
193 Status = TRUE;
194 break;
195
196 /* DbgCommandString */
197 case BREAKPOINT_COMMAND_STRING:
198
199 /* Call the worker routine */
200 KdpCommandString((ULONG)ExceptionRecord->
201 ExceptionInformation[1],
202 (LPSTR)ExceptionRecord->
203 ExceptionInformation[2],
204 PreviousMode,
205 ContextRecord,
206 TrapFrame,
207 ExceptionFrame);
208 Status = TRUE;
209
210 /* Anything else, do nothing */
211 default:
212
213 /* Get out */
214 break;
215 }
216
217 /*
218 * If the PC was not updated, we'll increment it ourselves so execution
219 * continues past the breakpoint.
220 */
221 if (ProgramCounter == KeGetContextPc(ContextRecord))
222 {
223 /* Update it */
224 KeSetContextPc(ContextRecord,
225 ProgramCounter + KD_BREAKPOINT_SIZE);
226 }
227 }
228 else
229 {
230 /* Call the worker routine */
231 Status = KdpReport(TrapFrame,
232 ExceptionFrame,
233 ExceptionRecord,
234 ContextRecord,
235 PreviousMode,
236 SecondChanceException);
237 }
238
239 /* Return TRUE or FALSE to caller */
240 return Status;
241 }
242
243 BOOLEAN
244 NTAPI
245 KdpStub(IN PKTRAP_FRAME TrapFrame,
246 IN PKEXCEPTION_FRAME ExceptionFrame,
247 IN PEXCEPTION_RECORD ExceptionRecord,
248 IN PCONTEXT ContextRecord,
249 IN KPROCESSOR_MODE PreviousMode,
250 IN BOOLEAN SecondChanceException)
251 {
252 ULONG ExceptionCommand = ExceptionRecord->ExceptionInformation[0];
253
254 /* Check if this was a breakpoint due to DbgPrint or Load/UnloadSymbols */
255 if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) &&
256 (ExceptionRecord->NumberParameters > 0) &&
257 ((ExceptionCommand == BREAKPOINT_LOAD_SYMBOLS) ||
258 (ExceptionCommand == BREAKPOINT_UNLOAD_SYMBOLS) ||
259 (ExceptionCommand == BREAKPOINT_COMMAND_STRING) ||
260 (ExceptionCommand == BREAKPOINT_PRINT)))
261 {
262 /* This we can handle: simply bump the Program Counter */
263 KeSetContextPc(ContextRecord,
264 KeGetContextPc(ContextRecord) + KD_BREAKPOINT_SIZE);
265 return TRUE;
266 }
267 else if (KdPitchDebugger)
268 {
269 /* There's no debugger, fail. */
270 return FALSE;
271 }
272 else if ((KdAutoEnableOnEvent) &&
273 (KdPreviouslyEnabled) &&
274 !(KdDebuggerEnabled) &&
275 (NT_SUCCESS(KdEnableDebugger())) &&
276 (KdDebuggerEnabled))
277 {
278 /* Debugging was Auto-Enabled. We can now send this to KD. */
279 return KdpTrap(TrapFrame,
280 ExceptionFrame,
281 ExceptionRecord,
282 ContextRecord,
283 PreviousMode,
284 SecondChanceException);
285 }
286 else
287 {
288 /* FIXME: All we can do in this case is trace this exception */
289 return FALSE;
290 }
291 }