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 * Stefan Ginsberg (stefan.ginsberg@reactos.org)
10 /* INCLUDES ******************************************************************/
17 // Retrieves the ComponentId and Level for BREAKPOINT_PRINT
18 // and OutputString and OutputStringLength for BREAKPOINT_PROMPT.
25 #define KdpGetFirstParameter(Context) ((Context)->Ebx)
26 #define KdpGetSecondParameter(Context) ((Context)->Edi)
28 #elif defined(_M_AMD64)
33 #define KdpGetFirstParameter(Context) ((Context)->R8)
34 #define KdpGetSecondParameter(Context) ((Context)->R9)
41 #error Unsupported Architecture
44 /* FUNCTIONS *****************************************************************/
48 KdpReport(IN PKTRAP_FRAME TrapFrame
,
49 IN PKEXCEPTION_FRAME ExceptionFrame
,
50 IN PEXCEPTION_RECORD ExceptionRecord
,
51 IN PCONTEXT ContextRecord
,
52 IN KPROCESSOR_MODE PreviousMode
,
53 IN BOOLEAN SecondChanceException
)
55 BOOLEAN Entered
, Status
;
57 NTSTATUS ExceptionCode
= ExceptionRecord
->ExceptionCode
;
60 * Determine whether to pass the exception to the debugger.
61 * First, check if this is a "debug exception", meaning breakpoint
62 * (including debug service), single step and assertion failure exceptions.
64 if ((ExceptionCode
== STATUS_BREAKPOINT
) ||
65 (ExceptionCode
== STATUS_SINGLE_STEP
) ||
66 (ExceptionCode
== STATUS_ASSERTION_FAILURE
))
68 /* This is a debug exception; we always pass them to the debugger */
70 else if (NtGlobalFlag
& FLG_STOP_ON_EXCEPTION
)
73 * Not a debug exception, but the stop-on-exception flag is set,
74 * meaning the debugger requests that we pass it first chance
75 * exceptions. However, some exceptions are always passed to the
76 * exception handler first, namely exceptions with a code that isn't
77 * an error or warning code, and also exceptions with the special
78 * STATUS_PORT_DISCONNECTED code (an error code).
80 if ((SecondChanceException
== FALSE
) &&
81 ((ExceptionCode
== STATUS_PORT_DISCONNECTED
) ||
82 (NT_SUCCESS(ExceptionCode
))))
84 /* Let the exception handler, if any, try to handle it */
88 else if (SecondChanceException
== FALSE
)
91 * This isn't a debug exception and the stop-on-exception flag isn't
92 * set, so don't bother
97 /* Enter the debugger */
98 Entered
= KdEnterDebugger(TrapFrame
, ExceptionFrame
);
101 * Get the KPRCB and save the CPU Control State manually instead of
102 * using KiSaveProcessorState, since we already have a valid CONTEXT.
104 Prcb
= KeGetCurrentPrcb();
105 KiSaveProcessorControlState(&Prcb
->ProcessorState
);
106 RtlCopyMemory(&Prcb
->ProcessorState
.ContextFrame
,
110 /* Report the new state */
111 Status
= KdpReportExceptionStateChange(ExceptionRecord
,
112 &Prcb
->ProcessorState
.
114 SecondChanceException
);
116 /* Now restore the processor state, manually again. */
117 RtlCopyMemory(ContextRecord
,
118 &Prcb
->ProcessorState
.ContextFrame
,
120 KiRestoreProcessorControlState(&Prcb
->ProcessorState
);
122 /* Exit the debugger and clear the CTRL-C state */
123 KdExitDebugger(Entered
);
124 KdpControlCPressed
= FALSE
;
130 KdpTrap(IN PKTRAP_FRAME TrapFrame
,
131 IN PKEXCEPTION_FRAME ExceptionFrame
,
132 IN PEXCEPTION_RECORD ExceptionRecord
,
133 IN PCONTEXT ContextRecord
,
134 IN KPROCESSOR_MODE PreviousMode
,
135 IN BOOLEAN SecondChanceException
)
137 BOOLEAN Unload
= FALSE
;
138 ULONG_PTR ProgramCounter
, ReturnValue
;
139 BOOLEAN Status
= FALSE
;
142 * Check if we got a STATUS_BREAKPOINT with a SubID for Print, Prompt or
143 * Load/Unload symbols. Make sure it isn't a software breakpoints as those
144 * are handled by KdpReport.
146 if ((ExceptionRecord
->ExceptionCode
== STATUS_BREAKPOINT
) &&
147 (ExceptionRecord
->ExceptionInformation
[0] != BREAKPOINT_BREAK
))
149 /* Save Program Counter */
150 ProgramCounter
= KeGetContextPc(ContextRecord
);
152 /* Check what kind of operation was requested from us */
153 switch (ExceptionRecord
->ExceptionInformation
[0])
156 case BREAKPOINT_PRINT
:
158 /* Call the worker routine */
159 ReturnValue
= KdpPrint((ULONG
)KdpGetFirstParameter(ContextRecord
),
160 (ULONG
)KdpGetSecondParameter(ContextRecord
),
161 (LPSTR
)ExceptionRecord
->
162 ExceptionInformation
[1],
163 (USHORT
)ExceptionRecord
->
164 ExceptionInformation
[2],
170 /* Update the return value for the caller */
171 KeSetContextReturnRegister(ContextRecord
, ReturnValue
);
175 case BREAKPOINT_PROMPT
:
177 /* Call the worker routine */
178 ReturnValue
= KdpPrompt((LPSTR
)ExceptionRecord
->
179 ExceptionInformation
[1],
180 (USHORT
)ExceptionRecord
->
181 ExceptionInformation
[2],
182 (LPSTR
)KdpGetFirstParameter(ContextRecord
),
183 (USHORT
)KdpGetSecondParameter(ContextRecord
),
189 /* Update the return value for the caller */
190 KeSetContextReturnRegister(ContextRecord
, ReturnValue
);
193 /* DbgUnLoadImageSymbols */
194 case BREAKPOINT_UNLOAD_SYMBOLS
:
196 /* Drop into the load case below, with the unload parameter */
199 /* DbgLoadImageSymbols */
200 case BREAKPOINT_LOAD_SYMBOLS
:
202 /* Call the worker routine */
203 KdpSymbol((PSTRING
)ExceptionRecord
->
204 ExceptionInformation
[1],
205 (PKD_SYMBOLS_INFO
)ExceptionRecord
->
206 ExceptionInformation
[2],
215 /* DbgCommandString */
216 case BREAKPOINT_COMMAND_STRING
:
218 /* Call the worker routine */
219 KdpCommandString((ULONG
)ExceptionRecord
->
220 ExceptionInformation
[1],
221 (LPSTR
)ExceptionRecord
->
222 ExceptionInformation
[2],
229 /* Anything else, do nothing */
237 * If the PC was not updated, we'll increment it ourselves so execution
238 * continues past the breakpoint.
240 if (ProgramCounter
== KeGetContextPc(ContextRecord
))
243 KeSetContextPc(ContextRecord
,
244 ProgramCounter
+ KD_BREAKPOINT_SIZE
);
249 /* Call the worker routine */
250 Status
= KdpReport(TrapFrame
,
255 SecondChanceException
);
258 /* Return TRUE or FALSE to caller */
264 KdpStub(IN PKTRAP_FRAME TrapFrame
,
265 IN PKEXCEPTION_FRAME ExceptionFrame
,
266 IN PEXCEPTION_RECORD ExceptionRecord
,
267 IN PCONTEXT ContextRecord
,
268 IN KPROCESSOR_MODE PreviousMode
,
269 IN BOOLEAN SecondChanceException
)
271 ULONG ExceptionCommand
= ExceptionRecord
->ExceptionInformation
[0];
273 /* Check if this was a breakpoint due to DbgPrint or Load/UnloadSymbols */
274 if ((ExceptionRecord
->ExceptionCode
== STATUS_BREAKPOINT
) &&
275 (ExceptionRecord
->NumberParameters
> 0) &&
276 ((ExceptionCommand
== BREAKPOINT_LOAD_SYMBOLS
) ||
277 (ExceptionCommand
== BREAKPOINT_UNLOAD_SYMBOLS
) ||
278 (ExceptionCommand
== BREAKPOINT_COMMAND_STRING
) ||
279 (ExceptionCommand
== BREAKPOINT_PRINT
)))
281 /* This we can handle: simply bump the Program Counter */
282 KeSetContextPc(ContextRecord
,
283 KeGetContextPc(ContextRecord
) + KD_BREAKPOINT_SIZE
);
286 else if (KdPitchDebugger
)
288 /* There's no debugger, fail. */
291 else if ((KdAutoEnableOnEvent
) &&
292 (KdPreviouslyEnabled
) &&
293 !(KdDebuggerEnabled
) &&
294 (NT_SUCCESS(KdEnableDebugger())) &&
297 /* Debugging was Auto-Enabled. We can now send this to KD. */
298 return KdpTrap(TrapFrame
,
303 SecondChanceException
);
307 /* FIXME: All we can do in this case is trace this exception */
314 KdIsThisAKdTrap(IN PEXCEPTION_RECORD ExceptionRecord
,
316 IN KPROCESSOR_MODE PreviousMode
)
319 * Determine if this is a valid debug service call and make sure that
320 * it isn't a software breakpoint
322 if ((ExceptionRecord
->ExceptionCode
== STATUS_BREAKPOINT
) &&
323 (ExceptionRecord
->NumberParameters
> 0) &&
324 (ExceptionRecord
->ExceptionInformation
[0] != BREAKPOINT_BREAK
))
326 /* Then we have to handle it */
331 /* We don't have to handle it */