ReactOS  r76032
kdtrap.c
Go to the documentation of this file.
1 /*
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)
8  */
9 
10 /* INCLUDES ******************************************************************/
11 
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15 
16 //
17 // Retrieves the ComponentId and Level for BREAKPOINT_PRINT
18 // and OutputString and OutputStringLength for BREAKPOINT_PROMPT.
19 //
20 #if defined(_X86_)
21 
22 //
23 // EBX/EDI on x86
24 //
25 #define KdpGetParameterThree(Context) ((Context)->Ebx)
26 #define KdpGetParameterFour(Context) ((Context)->Edi)
27 
28 #elif defined(_AMD64_)
29 
30 //
31 // R8/R9 on AMD64
32 //
33 #define KdpGetParameterThree(Context) ((Context)->R8)
34 #define KdpGetParameterFour(Context) ((Context)->R9)
35 
36 #elif defined(_ARM_)
37 
38 //
39 // R3/R4 on ARM
40 //
41 #define KdpGetParameterThree(Context) ((Context)->R3)
42 #define KdpGetParameterFour(Context) ((Context)->R4)
43 
44 #else
45 #error Unsupported Architecture
46 #endif
47 
48 /* FUNCTIONS *****************************************************************/
49 
50 BOOLEAN
51 NTAPI
53  IN PKEXCEPTION_FRAME ExceptionFrame,
54  IN PEXCEPTION_RECORD ExceptionRecord,
57  IN BOOLEAN SecondChanceException)
58 {
60  PKPRCB Prcb;
61  NTSTATUS ExceptionCode;
62 
63  /*
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.
67  */
68  ExceptionCode = ExceptionRecord->ExceptionCode;
69  if ((ExceptionCode == STATUS_BREAKPOINT) ||
70  (ExceptionCode == STATUS_SINGLE_STEP) ||
71  (ExceptionCode == STATUS_ASSERTION_FAILURE))
72  {
73  /* This is a debug exception; we always pass them to the debugger */
74  }
76  {
77  /*
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).
84  */
85  if ((SecondChanceException == FALSE) &&
86  ((ExceptionCode == STATUS_PORT_DISCONNECTED) ||
87  (NT_SUCCESS(ExceptionCode))))
88  {
89  /* Let the exception handler, if any, try to handle it */
90  return FALSE;
91  }
92  }
93  else if (SecondChanceException == FALSE)
94  {
95  /*
96  * This isn't a debug exception and the stop-on-exception flag isn't set,
97  * so don't bother handling it
98  */
99  return FALSE;
100  }
101 
102  /* Enter the debugger */
103  Enable = KdEnterDebugger(TrapFrame, ExceptionFrame);
104 
105  /*
106  * Get the KPRCB and save the CPU Control State manually instead of
107  * using KiSaveProcessorState, since we already have a valid CONTEXT.
108  */
109  Prcb = KeGetCurrentPrcb();
112  ContextRecord,
113  sizeof(CONTEXT));
114 
115  /* Report the new state */
116  Handled = KdpReportExceptionStateChange(ExceptionRecord,
117  &Prcb->ProcessorState.
118  ContextFrame,
119  SecondChanceException);
120 
121  /* Now restore the processor state, manually again. */
122  KdpMoveMemory(ContextRecord,
124  sizeof(CONTEXT));
126 
127  /* Exit the debugger and clear the CTRL-C state */
128  KdExitDebugger(Enable);
130  return Handled;
131 }
132 
133 BOOLEAN
134 NTAPI
136  IN PKEXCEPTION_FRAME ExceptionFrame,
137  IN PEXCEPTION_RECORD ExceptionRecord,
140  IN BOOLEAN SecondChanceException)
141 {
142  BOOLEAN Unload;
143  ULONG_PTR ProgramCounter;
145  NTSTATUS ReturnStatus;
147 
148  /*
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.
152  */
153  if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) &&
154  (ExceptionRecord->ExceptionInformation[0] != BREAKPOINT_BREAK))
155  {
156  /* Save Program Counter */
157  ProgramCounter = KeGetContextPc(ContextRecord);
158 
159  /* Check what kind of operation was requested from us */
160  Unload = FALSE;
161  switch (ExceptionRecord->ExceptionInformation[0])
162  {
163  /* DbgPrint */
164  case BREAKPOINT_PRINT:
165 
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],
171  PreviousMode,
172  TrapFrame,
173  ExceptionFrame,
174  &Handled);
175 
176  /* Update the return value for the caller */
177  KeSetContextReturnRegister(ContextRecord,
178  ReturnStatus);
179  break;
180 
181  /* DbgPrompt */
182  case BREAKPOINT_PROMPT:
183 
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),
189  PreviousMode,
190  TrapFrame,
191  ExceptionFrame);
192  Handled = TRUE;
193 
194  /* Update the return value for the caller */
195  KeSetContextReturnRegister(ContextRecord, ReturnLength);
196  break;
197 
198  /* DbgUnLoadImageSymbols */
200 
201  /* Drop into the load case below, with the unload parameter */
202  Unload = TRUE;
203 
204  /* DbgLoadImageSymbols */
206 
207  /* Call the worker routine */
208  KdpSymbol((PSTRING)ExceptionRecord->
209  ExceptionInformation[1],
210  (PKD_SYMBOLS_INFO)ExceptionRecord->
211  ExceptionInformation[2],
212  Unload,
213  PreviousMode,
214  ContextRecord,
215  TrapFrame,
216  ExceptionFrame);
217  Handled = TRUE;
218  break;
219 
220  /* DbgCommandString */
222 
223  /* Call the worker routine */
224  KdpCommandString((PSTRING)ExceptionRecord->
225  ExceptionInformation[1],
226  (PSTRING)ExceptionRecord->
227  ExceptionInformation[2],
228  PreviousMode,
229  ContextRecord,
230  TrapFrame,
231  ExceptionFrame);
232  Handled = TRUE;
233  break;
234 
235  /* Anything else, do nothing */
236  default:
237 
238  /* Invalid debug service! Don't handle this! */
239  Handled = FALSE;
240  break;
241  }
242 
243  /*
244  * If the PC was not updated, we'll increment it ourselves so execution
245  * continues past the breakpoint.
246  */
247  if (ProgramCounter == KeGetContextPc(ContextRecord))
248  {
249  /* Update it */
250  KeSetContextPc(ContextRecord,
251  ProgramCounter + KD_BREAKPOINT_SIZE);
252  }
253  }
254  else
255  {
256  /* Call the worker routine */
257  Handled = KdpReport(TrapFrame,
258  ExceptionFrame,
259  ExceptionRecord,
260  ContextRecord,
261  PreviousMode,
262  SecondChanceException);
263  }
264 
265  /* Return TRUE or FALSE to caller */
266  return Handled;
267 }
268 
269 BOOLEAN
270 NTAPI
272  IN PKEXCEPTION_FRAME ExceptionFrame,
273  IN PEXCEPTION_RECORD ExceptionRecord,
276  IN BOOLEAN SecondChanceException)
277 {
278  ULONG_PTR ExceptionCommand;
279 
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)))
288  {
289  /* This we can handle: simply bump the Program Counter */
290  KeSetContextPc(ContextRecord,
291  KeGetContextPc(ContextRecord) + KD_BREAKPOINT_SIZE);
292  return TRUE;
293  }
294  else if (KdPitchDebugger)
295  {
296  /* There's no debugger, fail. */
297  return FALSE;
298  }
299  else if ((KdAutoEnableOnEvent) &&
301  !(KdDebuggerEnabled) &&
304  {
305  /* Debugging was Auto-Enabled. We can now send this to KD. */
306  return KdpTrap(TrapFrame,
307  ExceptionFrame,
308  ExceptionRecord,
309  ContextRecord,
310  PreviousMode,
311  SecondChanceException);
312  }
313  else
314  {
315  /* FIXME: All we can do in this case is trace this exception */
316  return FALSE;
317  }
318 }
319 
320 BOOLEAN
321 NTAPI
325 {
326  /*
327  * Determine if this is a valid debug service call and make sure that
328  * it isn't a software breakpoint
329  */
330  if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) &&
331  (ExceptionRecord->NumberParameters > 0) &&
332  (ExceptionRecord->ExceptionInformation[0] != BREAKPOINT_BREAK))
333  {
334  /* Then we have to handle it */
335  return TRUE;
336  }
337  else
338  {
339  /* We don't have to handle it */
340  return FALSE;
341  }
342 }
BOOLEAN NTAPI KdpStub(IN PKTRAP_FRAME TrapFrame, IN PKEXCEPTION_FRAME ExceptionFrame, IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT ContextRecord, IN KPROCESSOR_MODE PreviousMode, IN BOOLEAN SecondChanceException)
Definition: kdtrap.c:271
IN CINT OUT PVOID IN ULONG OUT PULONG ReturnLength
Definition: dumpinfo.c:39
#define IN
Definition: typedefs.h:38
#define TRUE
Definition: types.h:120
BOOLEAN Enable
Definition: acefiex.h:245
BOOLEAN NTAPI KdpTrap(IN PKTRAP_FRAME TrapFrame, IN PKEXCEPTION_FRAME ExceptionFrame, IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT ContextRecord, IN KPROCESSOR_MODE PreviousMode, IN BOOLEAN SecondChanceException)
Definition: kdtrap.c:135
VOID NTAPI Unload(PDRIVER_OBJECT DriverObject)
Definition: csqtest.c:160
#define KeSetContextReturnRegister(Context, ReturnValue)
Definition: ke.h:115
BOOLEAN KdAutoEnableOnEvent
Definition: kddata.c:84
BOOLEAN NTAPI KdIsThisAKdTrap(IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT Context, IN KPROCESSOR_MODE PreviousMode)
Definition: kdtrap.c:322
#define STATUS_SINGLE_STEP
Definition: ntstatus.h:173
FORCEINLINE struct _KPRCB * KeGetCurrentPrcb(VOID)
Definition: ketypes.h:1054
USHORT NTAPI KdpPrompt(IN LPSTR PromptString, IN USHORT PromptLength, OUT LPSTR ResponseString, IN USHORT MaximumResponseLength, IN KPROCESSOR_MODE PreviousMode, IN PKTRAP_FRAME TrapFrame, IN PKEXCEPTION_FRAME ExceptionFrame)
BOOLEAN KdPreviouslyEnabled
Definition: kddata.c:87
VOID NTAPI KdExitDebugger(IN BOOLEAN Enable)
Definition: kdapi.c:1924
char * LPSTR
Definition: xmlstorage.h:182
BOOLEAN NTAPI KdpReport(IN PKTRAP_FRAME TrapFrame, IN PKEXCEPTION_FRAME ExceptionFrame, IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT ContextRecord, IN KPROCESSOR_MODE PreviousMode, IN BOOLEAN SecondChanceException)
Definition: kdtrap.c:52
uint32_t ULONG_PTR
Definition: typedefs.h:63
VOID NTAPI KdpCommandString(IN PSTRING NameString, IN PSTRING CommandString, IN KPROCESSOR_MODE PreviousMode, IN PCONTEXT ContextRecord, IN PKTRAP_FRAME TrapFrame, IN PKEXCEPTION_FRAME ExceptionFrame)
Definition: kdprint.c:133
BOOLEAN KdpControlCPressed
Definition: kddata.c:68
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define FALSE
Definition: types.h:117
#define FLG_STOP_ON_EXCEPTION
Definition: pstypes.h:56
#define BREAKPOINT_UNLOAD_SYMBOLS
Definition: kdtypes.h:54
CONTEXT ContextFrame
Definition: ketypes.h:531
#define STATUS_BREAKPOINT
Definition: ntstatus.h:172
BOOLEAN KdDebuggerEnabled
Definition: kdmain.c:16
VOID NTAPI KiRestoreProcessorControlState(IN PKPROCESSOR_STATE ProcessorState)
#define KeGetContextPc(Context)
Definition: ke.h:100
#define BREAKPOINT_PROMPT
Definition: kdtypes.h:52
#define STATUS_ASSERTION_FAILURE
Definition: ntstatus.h:946
unsigned char BOOLEAN
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103
VOID NTAPI KdpSymbol(IN PSTRING DllPath, IN PKD_SYMBOLS_INFO SymbolInfo, IN BOOLEAN Unload, IN KPROCESSOR_MODE PreviousMode, IN PCONTEXT ContextRecord, IN PKTRAP_FRAME TrapFrame, IN PKEXCEPTION_FRAME ExceptionFrame)
Definition: kdprint.c:172
_In_ BOOLEAN Handled
Definition: ketypes.h:337
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:24
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
NTSTATUS NTAPI KdEnableDebugger(VOID)
Definition: kdmain.c:312
KPROCESSOR_STATE ProcessorState
Definition: ketypes.h:579
_IRQL_requires_same_ _In_ PVOID _Inout_ struct _CONTEXT * ContextRecord
Definition: ntbasedef.h:653
#define BREAKPOINT_PRINT
Definition: kdtypes.h:51
VOID NTAPI KiSaveProcessorControlState(OUT PKPROCESSOR_STATE ProcessorState)
Definition: cpu.c:382
BOOLEAN KdPitchDebugger
Definition: kdmain.c:21
LONG NTSTATUS
Definition: DriverTester.h:11
unsigned short USHORT
Definition: pedump.c:61
#define BREAKPOINT_LOAD_SYMBOLS
Definition: kdtypes.h:53
VOID NTAPI KdpMoveMemory(IN PVOID Destination, IN PVOID Source, IN SIZE_T Length)
Definition: kdapi.c:20
#define STATUS_PORT_DISCONNECTED
Definition: ntstatus.h:277
BOOLEAN NTAPI KdpReportExceptionStateChange(IN PEXCEPTION_RECORD ExceptionRecord, IN OUT PCONTEXT Context, IN BOOLEAN SecondChanceException)
Definition: kdapi.c:1730
unsigned int ULONG
Definition: retypes.h:1
NTSTATUS NTAPI KdpPrint(IN ULONG ComponentId, IN ULONG Level, IN LPSTR String, IN USHORT Length, IN KPROCESSOR_MODE PreviousMode, IN PKTRAP_FRAME TrapFrame, IN PKEXCEPTION_FRAME ExceptionFrame, OUT PBOOLEAN Handled)
Definition: kdprint.c:317
#define BREAKPOINT_COMMAND_STRING
Definition: kdtypes.h:55
BOOLEAN NTAPI KdEnterDebugger(IN PKTRAP_FRAME TrapFrame, IN PKEXCEPTION_FRAME ExceptionFrame)
Definition: kdapi.c:1871
#define KD_BREAKPOINT_SIZE
Definition: ke.h:94
#define KeSetContextPc(Context, ProgramCounter)
Definition: ke.h:103
ULONG NtGlobalFlag
Definition: init.c:51
#define BREAKPOINT_BREAK
Definition: kdtypes.h:50