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 KdpGetParameterThree(Context) ((Context)->Ebx)
26 #define KdpGetParameterFour(Context) ((Context)->Edi)
28 #elif defined(_AMD64_)
33 #define KdpGetParameterThree(Context) ((Context)->R8)
34 #define KdpGetParameterFour(Context) ((Context)->R9)
41 #define KdpGetParameterThree(Context) ((Context)->R3)
42 #define KdpGetParameterFour(Context) ((Context)->R4)
45 #error Unsupported Architecture
48 /* FUNCTIONS *****************************************************************/
52 KdpReport(IN PKTRAP_FRAME TrapFrame
,
53 IN PKEXCEPTION_FRAME ExceptionFrame
,
54 IN PEXCEPTION_RECORD ExceptionRecord
,
55 IN PCONTEXT ContextRecord
,
56 IN KPROCESSOR_MODE PreviousMode
,
57 IN BOOLEAN SecondChanceException
)
59 BOOLEAN Enable
, Handled
;
61 NTSTATUS ExceptionCode
;
64 * Determine whether to pass the exception to the debugger.
65 * First, check if this is a "debug exception", meaning breakpoint
66 * (including debug service), single step and assertion failure exceptions.
68 ExceptionCode
= ExceptionRecord
->ExceptionCode
;
69 if ((ExceptionCode
== STATUS_BREAKPOINT
) ||
70 (ExceptionCode
== STATUS_SINGLE_STEP
) ||
71 (ExceptionCode
== STATUS_ASSERTION_FAILURE
))
73 /* This is a debug exception; we always pass them to the debugger */
75 else if (NtGlobalFlag
& FLG_STOP_ON_EXCEPTION
)
78 * Not a debug exception, but the stop-on-exception flag is set,
79 * meaning the debugger requests that we pass it first chance
80 * exceptions. However, some exceptions are always passed to the
81 * exception handler first, namely exceptions with a code that isn't
82 * an error or warning code, and also exceptions with the special
83 * STATUS_PORT_DISCONNECTED code (an error code).
85 if ((SecondChanceException
== FALSE
) &&
86 ((ExceptionCode
== STATUS_PORT_DISCONNECTED
) ||
87 (NT_SUCCESS(ExceptionCode
))))
89 /* Let the exception handler, if any, try to handle it */
93 else if (SecondChanceException
== FALSE
)
96 * This isn't a debug exception and the stop-on-exception flag isn't set,
97 * so don't bother handling it
102 /* Enter the debugger */
103 Enable
= KdEnterDebugger(TrapFrame
, ExceptionFrame
);
106 * Get the KPRCB and save the CPU Control State manually instead of
107 * using KiSaveProcessorState, since we already have a valid CONTEXT.
109 Prcb
= KeGetCurrentPrcb();
110 KiSaveProcessorControlState(&Prcb
->ProcessorState
);
111 KdpMoveMemory(&Prcb
->ProcessorState
.ContextFrame
,
115 /* Report the new state */
116 Handled
= KdpReportExceptionStateChange(ExceptionRecord
,
117 &Prcb
->ProcessorState
.
119 SecondChanceException
);
121 /* Now restore the processor state, manually again. */
122 KdpMoveMemory(ContextRecord
,
123 &Prcb
->ProcessorState
.ContextFrame
,
125 KiRestoreProcessorControlState(&Prcb
->ProcessorState
);
127 /* Exit the debugger and clear the CTRL-C state */
128 KdExitDebugger(Enable
);
129 KdpControlCPressed
= FALSE
;
135 KdpTrap(IN PKTRAP_FRAME TrapFrame
,
136 IN PKEXCEPTION_FRAME ExceptionFrame
,
137 IN PEXCEPTION_RECORD ExceptionRecord
,
138 IN PCONTEXT ContextRecord
,
139 IN KPROCESSOR_MODE PreviousMode
,
140 IN BOOLEAN SecondChanceException
)
143 ULONG_PTR ProgramCounter
;
145 NTSTATUS ReturnStatus
;
149 * Check if we got a STATUS_BREAKPOINT with a SubID for Print, Prompt or
150 * Load/Unload symbols. Make sure it isn't a software breakpoints as those
151 * are handled by KdpReport.
153 if ((ExceptionRecord
->ExceptionCode
== STATUS_BREAKPOINT
) &&
154 (ExceptionRecord
->ExceptionInformation
[0] != BREAKPOINT_BREAK
))
156 /* Save Program Counter */
157 ProgramCounter
= KeGetContextPc(ContextRecord
);
159 /* Check what kind of operation was requested from us */
161 switch (ExceptionRecord
->ExceptionInformation
[0])
164 case BREAKPOINT_PRINT
:
166 /* Call the worker routine */
167 ReturnStatus
= KdpPrint((ULONG
)KdpGetParameterThree(ContextRecord
),
168 (ULONG
)KdpGetParameterFour(ContextRecord
),
169 (LPSTR
)ExceptionRecord
->ExceptionInformation
[1],
170 (USHORT
)ExceptionRecord
->ExceptionInformation
[2],
176 /* Update the return value for the caller */
177 KeSetContextReturnRegister(ContextRecord
,
182 case BREAKPOINT_PROMPT
:
184 /* Call the worker routine */
185 ReturnLength
= KdpPrompt((LPSTR
)ExceptionRecord
->ExceptionInformation
[1],
186 (USHORT
)ExceptionRecord
->ExceptionInformation
[2],
187 (LPSTR
)KdpGetParameterThree(ContextRecord
),
188 (USHORT
)KdpGetParameterFour(ContextRecord
),
194 /* Update the return value for the caller */
195 KeSetContextReturnRegister(ContextRecord
, ReturnLength
);
198 /* DbgUnLoadImageSymbols */
199 case BREAKPOINT_UNLOAD_SYMBOLS
:
201 /* Drop into the load case below, with the unload parameter */
204 /* DbgLoadImageSymbols */
205 case BREAKPOINT_LOAD_SYMBOLS
:
207 /* Call the worker routine */
208 KdpSymbol((PSTRING
)ExceptionRecord
->
209 ExceptionInformation
[1],
210 (PKD_SYMBOLS_INFO
)ExceptionRecord
->
211 ExceptionInformation
[2],
220 /* DbgCommandString */
221 case BREAKPOINT_COMMAND_STRING
:
223 /* Call the worker routine */
224 KdpCommandString((PSTRING
)ExceptionRecord
->
225 ExceptionInformation
[1],
226 (PSTRING
)ExceptionRecord
->
227 ExceptionInformation
[2],
235 /* Anything else, do nothing */
238 /* Invalid debug service! Don't handle this! */
244 * If the PC was not updated, we'll increment it ourselves so execution
245 * continues past the breakpoint.
247 if (ProgramCounter
== KeGetContextPc(ContextRecord
))
250 KeSetContextPc(ContextRecord
,
251 ProgramCounter
+ KD_BREAKPOINT_SIZE
);
256 /* Call the worker routine */
257 Handled
= KdpReport(TrapFrame
,
262 SecondChanceException
);
265 /* Return TRUE or FALSE to caller */
271 KdpStub(IN PKTRAP_FRAME TrapFrame
,
272 IN PKEXCEPTION_FRAME ExceptionFrame
,
273 IN PEXCEPTION_RECORD ExceptionRecord
,
274 IN PCONTEXT ContextRecord
,
275 IN KPROCESSOR_MODE PreviousMode
,
276 IN BOOLEAN SecondChanceException
)
278 ULONG_PTR ExceptionCommand
;
280 /* Check if this was a breakpoint due to DbgPrint or Load/UnloadSymbols */
281 ExceptionCommand
= ExceptionRecord
->ExceptionInformation
[0];
282 if ((ExceptionRecord
->ExceptionCode
== STATUS_BREAKPOINT
) &&
283 (ExceptionRecord
->NumberParameters
> 0) &&
284 ((ExceptionCommand
== BREAKPOINT_LOAD_SYMBOLS
) ||
285 (ExceptionCommand
== BREAKPOINT_UNLOAD_SYMBOLS
) ||
286 (ExceptionCommand
== BREAKPOINT_COMMAND_STRING
) ||
287 (ExceptionCommand
== BREAKPOINT_PRINT
)))
289 /* This we can handle: simply bump the Program Counter */
290 KeSetContextPc(ContextRecord
,
291 KeGetContextPc(ContextRecord
) + KD_BREAKPOINT_SIZE
);
294 else if (KdPitchDebugger
)
296 /* There's no debugger, fail. */
299 else if ((KdAutoEnableOnEvent
) &&
300 (KdPreviouslyEnabled
) &&
301 !(KdDebuggerEnabled
) &&
302 (NT_SUCCESS(KdEnableDebugger())) &&
305 /* Debugging was Auto-Enabled. We can now send this to KD. */
306 return KdpTrap(TrapFrame
,
311 SecondChanceException
);
315 /* FIXME: All we can do in this case is trace this exception */
322 KdIsThisAKdTrap(IN PEXCEPTION_RECORD ExceptionRecord
,
324 IN KPROCESSOR_MODE PreviousMode
)
327 * Determine if this is a valid debug service call and make sure that
328 * it isn't a software breakpoint
330 if ((ExceptionRecord
->ExceptionCode
== STATUS_BREAKPOINT
) &&
331 (ExceptionRecord
->NumberParameters
> 0) &&
332 (ExceptionRecord
->ExceptionInformation
[0] != BREAKPOINT_BREAK
))
334 /* Then we have to handle it */
339 /* We don't have to handle it */