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