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
;
139 BOOLEAN Status
= FALSE
;
140 NTSTATUS ReturnStatus
;
144 * Check if we got a STATUS_BREAKPOINT with a SubID for Print, Prompt or
145 * Load/Unload symbols. Make sure it isn't a software breakpoints as those
146 * are handled by KdpReport.
148 if ((ExceptionRecord
->ExceptionCode
== STATUS_BREAKPOINT
) &&
149 (ExceptionRecord
->ExceptionInformation
[0] != BREAKPOINT_BREAK
))
151 /* Save Program Counter */
152 ProgramCounter
= KeGetContextPc(ContextRecord
);
154 /* Check what kind of operation was requested from us */
155 switch (ExceptionRecord
->ExceptionInformation
[0])
158 case BREAKPOINT_PRINT
:
160 /* Call the worker routine */
161 ReturnStatus
= KdpPrint((ULONG
)KdpGetFirstParameter(ContextRecord
),
162 (ULONG
)KdpGetSecondParameter(ContextRecord
),
163 (LPSTR
)ExceptionRecord
->
164 ExceptionInformation
[1],
165 (USHORT
)ExceptionRecord
->
166 ExceptionInformation
[2],
172 /* Update the return value for the caller */
173 KeSetContextReturnRegister(ContextRecord
, ReturnStatus
);
177 case BREAKPOINT_PROMPT
:
179 /* Call the worker routine */
180 ReturnLength
= KdpPrompt((LPSTR
)ExceptionRecord
->
181 ExceptionInformation
[1],
182 (USHORT
)ExceptionRecord
->
183 ExceptionInformation
[2],
184 (LPSTR
)KdpGetFirstParameter(ContextRecord
),
185 (USHORT
)KdpGetSecondParameter(ContextRecord
),
191 /* Update the return value for the caller */
192 KeSetContextReturnRegister(ContextRecord
, ReturnLength
);
195 /* DbgUnLoadImageSymbols */
196 case BREAKPOINT_UNLOAD_SYMBOLS
:
198 /* Drop into the load case below, with the unload parameter */
201 /* DbgLoadImageSymbols */
202 case BREAKPOINT_LOAD_SYMBOLS
:
204 /* Call the worker routine */
205 KdpSymbol((PSTRING
)ExceptionRecord
->
206 ExceptionInformation
[1],
207 (PKD_SYMBOLS_INFO
)ExceptionRecord
->
208 ExceptionInformation
[2],
217 /* DbgCommandString */
218 case BREAKPOINT_COMMAND_STRING
:
220 /* Call the worker routine */
221 KdpCommandString((ULONG
)ExceptionRecord
->
222 ExceptionInformation
[1],
223 (LPSTR
)ExceptionRecord
->
224 ExceptionInformation
[2],
231 /* Anything else, do nothing */
239 * If the PC was not updated, we'll increment it ourselves so execution
240 * continues past the breakpoint.
242 if (ProgramCounter
== KeGetContextPc(ContextRecord
))
245 KeSetContextPc(ContextRecord
,
246 ProgramCounter
+ KD_BREAKPOINT_SIZE
);
251 /* Call the worker routine */
252 Status
= KdpReport(TrapFrame
,
257 SecondChanceException
);
260 /* Return TRUE or FALSE to caller */
266 KdpStub(IN PKTRAP_FRAME TrapFrame
,
267 IN PKEXCEPTION_FRAME ExceptionFrame
,
268 IN PEXCEPTION_RECORD ExceptionRecord
,
269 IN PCONTEXT ContextRecord
,
270 IN KPROCESSOR_MODE PreviousMode
,
271 IN BOOLEAN SecondChanceException
)
273 ULONG ExceptionCommand
= ExceptionRecord
->ExceptionInformation
[0];
275 /* Check if this was a breakpoint due to DbgPrint or Load/UnloadSymbols */
276 if ((ExceptionRecord
->ExceptionCode
== STATUS_BREAKPOINT
) &&
277 (ExceptionRecord
->NumberParameters
> 0) &&
278 ((ExceptionCommand
== BREAKPOINT_LOAD_SYMBOLS
) ||
279 (ExceptionCommand
== BREAKPOINT_UNLOAD_SYMBOLS
) ||
280 (ExceptionCommand
== BREAKPOINT_COMMAND_STRING
) ||
281 (ExceptionCommand
== BREAKPOINT_PRINT
)))
283 /* This we can handle: simply bump the Program Counter */
284 KeSetContextPc(ContextRecord
,
285 KeGetContextPc(ContextRecord
) + KD_BREAKPOINT_SIZE
);
288 else if (KdPitchDebugger
)
290 /* There's no debugger, fail. */
293 else if ((KdAutoEnableOnEvent
) &&
294 (KdPreviouslyEnabled
) &&
295 !(KdDebuggerEnabled
) &&
296 (NT_SUCCESS(KdEnableDebugger())) &&
299 /* Debugging was Auto-Enabled. We can now send this to KD. */
300 return KdpTrap(TrapFrame
,
305 SecondChanceException
);
309 /* FIXME: All we can do in this case is trace this exception */
316 KdIsThisAKdTrap(IN PEXCEPTION_RECORD ExceptionRecord
,
318 IN KPROCESSOR_MODE PreviousMode
)
321 * Determine if this is a valid debug service call and make sure that
322 * it isn't a software breakpoint
324 if ((ExceptionRecord
->ExceptionCode
== STATUS_BREAKPOINT
) &&
325 (ExceptionRecord
->NumberParameters
> 0) &&
326 (ExceptionRecord
->ExceptionInformation
[0] != BREAKPOINT_BREAK
))
328 /* Then we have to handle it */
333 /* We don't have to handle it */