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
= ExceptionRecord
->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 if ((ExceptionCode
== STATUS_BREAKPOINT
) ||
69 (ExceptionCode
== STATUS_SINGLE_STEP
) ||
70 (ExceptionCode
== STATUS_ASSERTION_FAILURE
))
72 /* This is a debug exception; we always pass them to the debugger */
74 else if (NtGlobalFlag
& FLG_STOP_ON_EXCEPTION
)
77 * Not a debug exception, but the stop-on-exception flag is set,
78 * meaning the debugger requests that we pass it first chance
79 * exceptions. However, some exceptions are always passed to the
80 * exception handler first, namely exceptions with a code that isn't
81 * an error or warning code, and also exceptions with the special
82 * STATUS_PORT_DISCONNECTED code (an error code).
84 if ((SecondChanceException
== FALSE
) &&
85 ((ExceptionCode
== STATUS_PORT_DISCONNECTED
) ||
86 (NT_SUCCESS(ExceptionCode
))))
88 /* Let the exception handler, if any, try to handle it */
92 else if (SecondChanceException
== FALSE
)
95 * This isn't a debug exception and the stop-on-exception flag isn't
96 * set, so don't bother
101 /* Enter the debugger */
102 Enable
= KdEnterDebugger(TrapFrame
, ExceptionFrame
);
105 * Get the KPRCB and save the CPU Control State manually instead of
106 * using KiSaveProcessorState, since we already have a valid CONTEXT.
108 Prcb
= KeGetCurrentPrcb();
109 KiSaveProcessorControlState(&Prcb
->ProcessorState
);
110 RtlCopyMemory(&Prcb
->ProcessorState
.ContextFrame
,
114 /* Report the new state */
115 Handled
= KdpReportExceptionStateChange(ExceptionRecord
,
116 &Prcb
->ProcessorState
.
118 SecondChanceException
);
120 /* Now restore the processor state, manually again. */
121 RtlCopyMemory(ContextRecord
,
122 &Prcb
->ProcessorState
.ContextFrame
,
124 KiRestoreProcessorControlState(&Prcb
->ProcessorState
);
126 /* Exit the debugger and clear the CTRL-C state */
127 KdExitDebugger(Enable
);
128 KdpControlCPressed
= FALSE
;
134 KdpTrap(IN PKTRAP_FRAME TrapFrame
,
135 IN PKEXCEPTION_FRAME ExceptionFrame
,
136 IN PEXCEPTION_RECORD ExceptionRecord
,
137 IN PCONTEXT ContextRecord
,
138 IN KPROCESSOR_MODE PreviousMode
,
139 IN BOOLEAN SecondChanceException
)
141 BOOLEAN Unload
= FALSE
;
142 ULONG_PTR ProgramCounter
;
144 NTSTATUS ReturnStatus
;
148 * Check if we got a STATUS_BREAKPOINT with a SubID for Print, Prompt or
149 * Load/Unload symbols. Make sure it isn't a software breakpoints as those
150 * are handled by KdpReport.
152 if ((ExceptionRecord
->ExceptionCode
== STATUS_BREAKPOINT
) &&
153 (ExceptionRecord
->ExceptionInformation
[0] != BREAKPOINT_BREAK
))
155 /* Save Program Counter */
156 ProgramCounter
= KeGetContextPc(ContextRecord
);
158 /* Check what kind of operation was requested from us */
159 switch (ExceptionRecord
->ExceptionInformation
[0])
162 case BREAKPOINT_PRINT
:
164 /* Call the worker routine */
165 ReturnStatus
= KdpPrint((ULONG
)KdpGetParameterThree(ContextRecord
),
166 (ULONG
)KdpGetParameterFour(ContextRecord
),
167 (LPSTR
)ExceptionRecord
->
168 ExceptionInformation
[1],
169 (USHORT
)ExceptionRecord
->
170 ExceptionInformation
[2],
176 /* Update the return value for the caller */
177 KeSetContextReturnRegister(ContextRecord
, ReturnStatus
);
181 case BREAKPOINT_PROMPT
:
183 /* Call the worker routine */
184 ReturnLength
= KdpPrompt((LPSTR
)ExceptionRecord
->
185 ExceptionInformation
[1],
186 (USHORT
)ExceptionRecord
->
187 ExceptionInformation
[2],
188 (LPSTR
)KdpGetParameterThree(ContextRecord
),
189 (USHORT
)KdpGetParameterFour(ContextRecord
),
195 /* Update the return value for the caller */
196 KeSetContextReturnRegister(ContextRecord
, ReturnLength
);
199 /* DbgUnLoadImageSymbols */
200 case BREAKPOINT_UNLOAD_SYMBOLS
:
202 /* Drop into the load case below, with the unload parameter */
205 /* DbgLoadImageSymbols */
206 case BREAKPOINT_LOAD_SYMBOLS
:
208 /* Call the worker routine */
209 KdpSymbol((PSTRING
)ExceptionRecord
->
210 ExceptionInformation
[1],
211 (PKD_SYMBOLS_INFO
)ExceptionRecord
->
212 ExceptionInformation
[2],
221 /* DbgCommandString */
222 case BREAKPOINT_COMMAND_STRING
:
224 /* Call the worker routine */
225 KdpCommandString((PSTRING
)ExceptionRecord
->
226 ExceptionInformation
[1],
227 (PSTRING
)ExceptionRecord
->
228 ExceptionInformation
[2],
236 /* Anything else, do nothing */
239 /* Invalid debug service! Don't handle this! */
245 * If the PC was not updated, we'll increment it ourselves so execution
246 * continues past the breakpoint.
248 if (ProgramCounter
== KeGetContextPc(ContextRecord
))
251 KeSetContextPc(ContextRecord
,
252 ProgramCounter
+ KD_BREAKPOINT_SIZE
);
257 /* Call the worker routine */
258 Handled
= KdpReport(TrapFrame
,
263 SecondChanceException
);
266 /* Return TRUE or FALSE to caller */
272 KdpStub(IN PKTRAP_FRAME TrapFrame
,
273 IN PKEXCEPTION_FRAME ExceptionFrame
,
274 IN PEXCEPTION_RECORD ExceptionRecord
,
275 IN PCONTEXT ContextRecord
,
276 IN KPROCESSOR_MODE PreviousMode
,
277 IN BOOLEAN SecondChanceException
)
279 ULONG_PTR ExceptionCommand
= ExceptionRecord
->ExceptionInformation
[0];
281 /* Check if this was a breakpoint due to DbgPrint or Load/UnloadSymbols */
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 */