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