The real, definitive, Visual C++ support branch. Accept no substitutes
[reactos.git] / 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 second 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 Eip, Eax;
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 EIP */
103 Eip = ContextRecord->Eip;
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 Eax = KdpPrint(ContextRecord->Ebx,
113 ContextRecord->Edi,
114 (LPSTR)ExceptionRecord->ExceptionInformation[1],
115 (ULONG)ExceptionRecord->ExceptionInformation[2],
116 PreviousMode,
117 TrapFrame,
118 ExceptionFrame,
119 &Status);
120
121 /* Update the return value for the caller */
122 ContextRecord->Eax = Eax;
123 break;
124
125 /* DbgPrompt */
126 case BREAKPOINT_PROMPT:
127
128 /* Call the worker routine */
129 while (TRUE);
130 Eax = 0;
131 Status = TRUE;
132
133 /* Update the return value for the caller */
134 ContextRecord->Eax = Eax;
135 break;
136
137 /* DbgUnloadSymbols */
138 case BREAKPOINT_UNLOAD_SYMBOLS:
139
140 /* Drop into the load case below, with the unload parameter */
141 Unload = TRUE;
142
143 /* DbgLoadSymbols */
144 case BREAKPOINT_LOAD_SYMBOLS:
145
146 /* Call the worker routine */
147 KdpSymbol((PVOID)ExceptionRecord->ExceptionInformation[1],
148 (PVOID)ExceptionRecord->ExceptionInformation[2],
149 Unload,
150 PreviousMode,
151 ContextRecord,
152 TrapFrame,
153 ExceptionFrame);
154 Status = TRUE;
155 break;
156
157 /* DbgCommandString*/
158 case BREAKPOINT_COMMAND_STRING:
159
160 /* Call the worker routine */
161 while (TRUE);
162 Status = TRUE;
163
164 /* Anything else, do nothing */
165 default:
166
167 /* Get out */
168 break;
169 }
170
171 /*
172 * If EIP was not updated, we'll increment it ourselves so execution
173 * continues past the breakpoint.
174 */
175 if (ContextRecord->Eip == Eip) ContextRecord->Eip++;
176 }
177 else
178 {
179 /* Call the worker routine */
180 Status = KdpReport(TrapFrame,
181 ExceptionFrame,
182 ExceptionRecord,
183 ContextRecord,
184 PreviousMode,
185 SecondChanceException);
186 }
187
188 /* Return TRUE or FALSE to caller */
189 return Status;
190 }
191
192 BOOLEAN
193 NTAPI
194 KdpStub(IN PKTRAP_FRAME TrapFrame,
195 IN PKEXCEPTION_FRAME ExceptionFrame,
196 IN PEXCEPTION_RECORD ExceptionRecord,
197 IN PCONTEXT ContextRecord,
198 IN KPROCESSOR_MODE PreviousMode,
199 IN BOOLEAN SecondChanceException)
200 {
201 ULONG ExceptionCommand = ExceptionRecord->ExceptionInformation[0];
202
203 /* Check if this was a breakpoint due to DbgPrint or Load/UnloadSymbols */
204 if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) &&
205 (ExceptionRecord->NumberParameters > 0) &&
206 ((ExceptionCommand == BREAKPOINT_LOAD_SYMBOLS) ||
207 (ExceptionCommand == BREAKPOINT_UNLOAD_SYMBOLS) ||
208 (ExceptionCommand == BREAKPOINT_COMMAND_STRING) ||
209 (ExceptionCommand == BREAKPOINT_PRINT)))
210 {
211 /* This we can handle: simply bump EIP */
212 ContextRecord->Eip++;
213 return TRUE;
214 }
215 else if (KdPitchDebugger)
216 {
217 /* There's no debugger, fail. */
218 return FALSE;
219 }
220 else if ((KdAutoEnableOnEvent) &&
221 (KdPreviouslyEnabled) &&
222 !(KdDebuggerEnabled) &&
223 (KdEnableDebugger()) &&
224 (KdDebuggerEnabled))
225 {
226 /* Debugging was Auto-Enabled. We can now send this to KD. */
227 return KdpTrap(TrapFrame,
228 ExceptionFrame,
229 ExceptionRecord,
230 ContextRecord,
231 PreviousMode,
232 SecondChanceException);
233 }
234 else
235 {
236 /* FIXME: All we can do in this case is trace this exception */
237 return FALSE;
238 }
239 }