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)
9 /* INCLUDES ******************************************************************/
16 // Retrieves the ComponentId and Level for BREAKPOINT_PRINT
17 // and OutputString and OutputStringLength for BREAKPOINT_PROMPT.
24 #define KdpGetFirstParameter(Context) ((Context)->Ebx)
25 #define KdpGetSecondParameter(Context) ((Context)->Edi)
27 #elif defined(_M_AMD64)
32 #define KdpGetFirstParameter(Context) ((Context)->R8)
33 #define KdpGetSecondParameter(Context) ((Context)->R9)
40 #error Unsupported Architecture
43 /* FUNCTIONS *****************************************************************/
47 KdpReport(IN PKTRAP_FRAME TrapFrame
,
48 IN PKEXCEPTION_FRAME ExceptionFrame
,
49 IN PEXCEPTION_RECORD ExceptionRecord
,
50 IN PCONTEXT ContextRecord
,
51 IN KPROCESSOR_MODE PreviousMode
,
52 IN BOOLEAN SecondChanceException
)
54 BOOLEAN Entered
, Status
;
56 NTSTATUS ExceptionCode
= ExceptionRecord
->ExceptionCode
;
58 /* Check if this is single step or a breakpoint, or if we're forced to handle it */
59 if ((ExceptionCode
== STATUS_BREAKPOINT
) ||
60 (ExceptionCode
== STATUS_SINGLE_STEP
) ||
61 (ExceptionCode
== STATUS_ASSERTION_FAILURE
) ||
62 (NtGlobalFlag
& FLG_STOP_ON_EXCEPTION
))
64 /* Check if we can't really handle this */
65 if ((SecondChanceException
) ||
66 (ExceptionCode
== STATUS_PORT_DISCONNECTED
) ||
67 (NT_SUCCESS(ExceptionCode
)))
69 /* Return false to have someone else take care of the exception */
73 else if (SecondChanceException
)
75 /* We won't bother unless this is first chance */
79 /* Enter the debugger */
80 Entered
= KdEnterDebugger(TrapFrame
, ExceptionFrame
);
83 * Get the KPRCB and save the CPU Control State manually instead of
84 * using KiSaveProcessorState, since we already have a valid CONTEXT.
86 Prcb
= KeGetCurrentPrcb();
87 KiSaveProcessorControlState(&Prcb
->ProcessorState
);
88 RtlCopyMemory(&Prcb
->ProcessorState
.ContextFrame
,
92 /* Report the new state */
93 Status
= KdpReportExceptionStateChange(ExceptionRecord
,
94 &Prcb
->ProcessorState
.
96 SecondChanceException
);
98 /* Now restore the processor state, manually again. */
99 RtlCopyMemory(ContextRecord
,
100 &Prcb
->ProcessorState
.ContextFrame
,
102 KiRestoreProcessorControlState(&Prcb
->ProcessorState
);
104 /* Exit the debugger and clear the CTRL-C state */
105 KdExitDebugger(Entered
);
106 KdpControlCPressed
= FALSE
;
112 KdpTrap(IN PKTRAP_FRAME TrapFrame
,
113 IN PKEXCEPTION_FRAME ExceptionFrame
,
114 IN PEXCEPTION_RECORD ExceptionRecord
,
115 IN PCONTEXT ContextRecord
,
116 IN KPROCESSOR_MODE PreviousMode
,
117 IN BOOLEAN SecondChanceException
)
119 BOOLEAN Unload
= FALSE
;
120 ULONG_PTR ProgramCounter
, ReturnValue
;
121 BOOLEAN Status
= FALSE
;
124 * Check if we got a STATUS_BREAKPOINT with a SubID for Print, Prompt or
125 * Load/Unload symbols.
127 if ((ExceptionRecord
->ExceptionCode
== STATUS_BREAKPOINT
) &&
128 (ExceptionRecord
->ExceptionInformation
[0] != BREAKPOINT_BREAK
))
130 /* Save Program Counter */
131 ProgramCounter
= KeGetContextPc(ContextRecord
);
133 /* Check what kind of operation was requested from us */
134 switch (ExceptionRecord
->ExceptionInformation
[0])
137 case BREAKPOINT_PRINT
:
139 /* Call the worker routine */
140 ReturnValue
= KdpPrint((ULONG
)KdpGetFirstParameter(ContextRecord
),
141 (ULONG
)KdpGetSecondParameter(ContextRecord
),
142 (LPSTR
)ExceptionRecord
->
143 ExceptionInformation
[1],
144 (USHORT
)ExceptionRecord
->
145 ExceptionInformation
[2],
151 /* Update the return value for the caller */
152 KeSetContextReturnRegister(ContextRecord
, ReturnValue
);
156 case BREAKPOINT_PROMPT
:
158 /* Call the worker routine */
159 ReturnValue
= KdpPrompt((LPSTR
)ExceptionRecord
->
160 ExceptionInformation
[1],
161 (USHORT
)ExceptionRecord
->
162 ExceptionInformation
[2],
163 (LPSTR
)KdpGetFirstParameter(ContextRecord
),
164 (USHORT
)KdpGetSecondParameter(ContextRecord
),
170 /* Update the return value for the caller */
171 KeSetContextReturnRegister(ContextRecord
, ReturnValue
);
174 /* DbgUnLoadImageSymbols */
175 case BREAKPOINT_UNLOAD_SYMBOLS
:
177 /* Drop into the load case below, with the unload parameter */
180 /* DbgLoadImageSymbols */
181 case BREAKPOINT_LOAD_SYMBOLS
:
183 /* Call the worker routine */
184 KdpSymbol((PSTRING
)ExceptionRecord
->
185 ExceptionInformation
[1],
186 (PKD_SYMBOLS_INFO
)ExceptionRecord
->
187 ExceptionInformation
[2],
196 /* DbgCommandString */
197 case BREAKPOINT_COMMAND_STRING
:
199 /* Call the worker routine */
200 KdpCommandString((ULONG
)ExceptionRecord
->
201 ExceptionInformation
[1],
202 (LPSTR
)ExceptionRecord
->
203 ExceptionInformation
[2],
210 /* Anything else, do nothing */
218 * If the PC was not updated, we'll increment it ourselves so execution
219 * continues past the breakpoint.
221 if (ProgramCounter
== KeGetContextPc(ContextRecord
))
224 KeSetContextPc(ContextRecord
,
225 ProgramCounter
+ KD_BREAKPOINT_SIZE
);
230 /* Call the worker routine */
231 Status
= KdpReport(TrapFrame
,
236 SecondChanceException
);
239 /* Return TRUE or FALSE to caller */
245 KdpStub(IN PKTRAP_FRAME TrapFrame
,
246 IN PKEXCEPTION_FRAME ExceptionFrame
,
247 IN PEXCEPTION_RECORD ExceptionRecord
,
248 IN PCONTEXT ContextRecord
,
249 IN KPROCESSOR_MODE PreviousMode
,
250 IN BOOLEAN SecondChanceException
)
252 ULONG ExceptionCommand
= ExceptionRecord
->ExceptionInformation
[0];
254 /* Check if this was a breakpoint due to DbgPrint or Load/UnloadSymbols */
255 if ((ExceptionRecord
->ExceptionCode
== STATUS_BREAKPOINT
) &&
256 (ExceptionRecord
->NumberParameters
> 0) &&
257 ((ExceptionCommand
== BREAKPOINT_LOAD_SYMBOLS
) ||
258 (ExceptionCommand
== BREAKPOINT_UNLOAD_SYMBOLS
) ||
259 (ExceptionCommand
== BREAKPOINT_COMMAND_STRING
) ||
260 (ExceptionCommand
== BREAKPOINT_PRINT
)))
262 /* This we can handle: simply bump the Program Counter */
263 KeSetContextPc(ContextRecord
,
264 KeGetContextPc(ContextRecord
) + KD_BREAKPOINT_SIZE
);
267 else if (KdPitchDebugger
)
269 /* There's no debugger, fail. */
272 else if ((KdAutoEnableOnEvent
) &&
273 (KdPreviouslyEnabled
) &&
274 !(KdDebuggerEnabled
) &&
275 (NT_SUCCESS(KdEnableDebugger())) &&
278 /* Debugging was Auto-Enabled. We can now send this to KD. */
279 return KdpTrap(TrapFrame
,
284 SecondChanceException
);
288 /* FIXME: All we can do in this case is trace this exception */