- Fix incorrect NtSetDebugFilter behavior (Level below 32 should be converted into...
[reactos.git] / reactos / ntoskrnl / kd / kdmain.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/kd/kdinit.c
5 * PURPOSE: Kernel Debugger Initializtion
6 *
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
8 */
9
10 #include <ntoskrnl.h>
11 #define NDEBUG
12 #include <internal/debug.h>
13
14 /* VARIABLES ***************************************************************/
15
16 BOOLEAN KdDebuggerEnabled = FALSE;
17 BOOLEAN KdEnteredDebugger = FALSE;
18 BOOLEAN KdDebuggerNotPresent = TRUE;
19 BOOLEAN KiEnableTimerWatchdog = FALSE;
20 BOOLEAN KdBreakAfterSymbolLoad = FALSE;
21 BOOLEAN KdpBreakPending;
22 BOOLEAN KdPitchDebugger = TRUE;
23 VOID STDCALL PspDumpThreads(BOOLEAN SystemThreads);
24
25 typedef struct
26 {
27 ULONG ComponentId;
28 ULONG Level;
29 } KD_COMPONENT_DATA;
30 #define MAX_KD_COMPONENT_TABLE_ENTRIES 128
31 KD_COMPONENT_DATA KdComponentTable[MAX_KD_COMPONENT_TABLE_ENTRIES];
32 ULONG KdComponentTableEntries = 0;
33
34 /* PRIVATE FUNCTIONS *********************************************************/
35
36 ULONG
37 STDCALL
38 KdpServiceDispatcher(ULONG Service,
39 PVOID Buffer1,
40 ULONG Buffer1Length)
41 {
42 ULONG Result = 0;
43
44 switch (Service)
45 {
46 case BREAKPOINT_PRINT: /* DbgPrint */
47 Result = KdpPrintString(Buffer1, Buffer1Length);
48 break;
49
50 #ifdef DBG
51 case TAG('R', 'o', 's', ' '): /* ROS-INTERNAL */
52 {
53 switch ((ULONG)Buffer1)
54 {
55 case DumpNonPagedPool:
56 MiDebugDumpNonPagedPool(FALSE);
57 break;
58
59 case ManualBugCheck:
60 KEBUGCHECK(MANUALLY_INITIATED_CRASH);
61 break;
62
63 case DumpNonPagedPoolStats:
64 MiDebugDumpNonPagedPoolStats(FALSE);
65 break;
66
67 case DumpNewNonPagedPool:
68 MiDebugDumpNonPagedPool(TRUE);
69 break;
70
71 case DumpNewNonPagedPoolStats:
72 MiDebugDumpNonPagedPoolStats(TRUE);
73 break;
74
75 case DumpAllThreads:
76 PspDumpThreads(TRUE);
77 break;
78
79 case DumpUserThreads:
80 PspDumpThreads(FALSE);
81 break;
82
83 case EnterDebugger:
84 DbgBreakPoint();
85 break;
86
87 default:
88 break;
89 }
90 }
91 #endif
92 default:
93 HalDisplayString ("Invalid debug service call!\n");
94 break;
95 }
96
97 return Result;
98 }
99
100 BOOLEAN
101 NTAPI
102 KdpEnterDebuggerException(IN PKTRAP_FRAME TrapFrame,
103 IN PKEXCEPTION_FRAME ExceptionFrame,
104 IN PEXCEPTION_RECORD ExceptionRecord,
105 IN PCONTEXT Context,
106 IN KPROCESSOR_MODE PreviousMode,
107 IN BOOLEAN SecondChance)
108 {
109 KD_CONTINUE_TYPE Return;
110 ULONG ExceptionCommand = ExceptionRecord->ExceptionInformation[0];
111 #ifdef _M_IX86
112 ULONG EipOld;
113 #endif
114
115 /* Check if this was a breakpoint due to DbgPrint or Load/UnloadSymbols */
116 if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) &&
117 (ExceptionRecord->NumberParameters > 0) &&
118 ((ExceptionCommand == BREAKPOINT_LOAD_SYMBOLS) ||
119 (ExceptionCommand == BREAKPOINT_UNLOAD_SYMBOLS) ||
120 (ExceptionCommand == BREAKPOINT_COMMAND_STRING) ||
121 (ExceptionCommand == BREAKPOINT_PRINT)))
122 {
123 /* Check if this is a debug print */
124 if (ExceptionCommand == BREAKPOINT_PRINT)
125 {
126 /* Print the string */
127 KdpServiceDispatcher(BREAKPOINT_PRINT,
128 (PVOID)ExceptionRecord->ExceptionInformation[1],
129 ExceptionRecord->ExceptionInformation[2]);
130 }
131 else if (ExceptionCommand == BREAKPOINT_LOAD_SYMBOLS)
132 {
133 /* Load symbols. Currently implemented only for KDBG! */
134 KDB_SYMBOLFILE_HOOK((PANSI_STRING)ExceptionRecord->ExceptionInformation[1],
135 (PKD_SYMBOLS_INFO)ExceptionRecord->ExceptionInformation[2]);
136 }
137
138 /* This we can handle: simply bump EIP */
139 #ifdef _M_IX86
140 Context->Eip++;
141 #endif
142 return TRUE;
143 }
144
145 /* Get out of here if the Debugger isn't connected */
146 if (KdDebuggerNotPresent) return FALSE;
147
148 /* Save old EIP value */
149 #ifdef _M_IX86
150 EipOld = Context->Eip;
151 #endif
152
153 /* Call KDBG if available */
154 Return = KdbEnterDebuggerException(ExceptionRecord,
155 PreviousMode,
156 Context,
157 TrapFrame,
158 !SecondChance);
159
160 /* Bump EIP over int 3 if debugger did not already change it */
161 if (ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT)
162 {
163 #ifdef KDBG
164 if (Context->Eip == EipOld)
165 Context->Eip++;
166 #else
167 /* We simulate the original behaviour when KDBG is turned off.
168 Return var is set to kdHandleException, thus we always return FALSE */
169 #ifdef _M_IX86
170 Context->Eip = EipOld;
171 #endif
172 #endif
173 }
174
175 /* Convert return to BOOLEAN */
176 if (Return == kdContinue) return TRUE;
177 return FALSE;
178 }
179
180 BOOLEAN
181 NTAPI
182 KdpCallGdb(IN PKTRAP_FRAME TrapFrame,
183 IN PEXCEPTION_RECORD ExceptionRecord,
184 IN PCONTEXT Context)
185 {
186 KD_CONTINUE_TYPE Return = kdDoNotHandleException;
187
188 /* Get out of here if the Debugger isn't connected */
189 if (KdDebuggerNotPresent) return FALSE;
190
191 /* FIXME:
192 * Right now, the GDB wrapper seems to handle exceptions differntly
193 * from KDGB and both are called at different times, while the GDB
194 * one is only called once and that's it. I don't really have the knowledge
195 * to fix the GDB stub, so until then, we'll be using this hack
196 */
197 if (WrapperInitRoutine)
198 {
199 Return = WrapperTable.KdpExceptionRoutine(ExceptionRecord,
200 Context,
201 TrapFrame);
202 }
203
204 /* Convert return to BOOLEAN */
205 if (Return == kdContinue) return TRUE;
206 return FALSE;
207 }
208
209 /* PUBLIC FUNCTIONS *********************************************************/
210
211 /*
212 * @implemented
213 */
214 NTSTATUS
215 STDCALL
216 KdDisableDebugger(VOID)
217 {
218 KIRQL OldIrql;
219
220 /* Raise IRQL */
221 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
222
223 /* TODO: Disable any breakpoints */
224
225 /* Disable the Debugger */
226 KdDebuggerEnabled = FALSE;
227
228 /* Lower the IRQL */
229 KeLowerIrql(OldIrql);
230
231 /* Return success */
232 return STATUS_SUCCESS;
233 }
234
235 /*
236 * @implemented
237 */
238 NTSTATUS
239 STDCALL
240 KdEnableDebugger(VOID)
241 {
242 KIRQL OldIrql;
243
244 /* Raise IRQL */
245 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
246
247 /* TODO: Re-enable any breakpoints */
248
249 /* Enable the Debugger */
250 KdDebuggerEnabled = TRUE;
251
252 /* Lower the IRQL */
253 KeLowerIrql(OldIrql);
254
255 /* Return success */
256 return STATUS_SUCCESS;
257 }
258
259 /*
260 * @implemented
261 */
262 BOOLEAN
263 STDCALL
264 KdPollBreakIn(VOID)
265 {
266 return KdpBreakPending;
267 }
268
269 /*
270 * @unimplemented
271 */
272 NTSTATUS
273 STDCALL
274 KdPowerTransition(ULONG PowerState)
275 {
276 UNIMPLEMENTED;
277 return STATUS_NOT_IMPLEMENTED;
278 }
279
280 /*
281 * @unimplemented
282 */
283 NTSTATUS
284 NTAPI
285 KdChangeOption(IN KD_OPTION Option,
286 IN ULONG InBufferLength OPTIONAL,
287 IN PVOID InBuffer,
288 IN ULONG OutBufferLength OPTIONAL,
289 OUT PVOID OutBuffer,
290 OUT PULONG OutBufferRequiredLength OPTIONAL)
291 {
292 UNIMPLEMENTED;
293 return STATUS_NOT_IMPLEMENTED;
294 }
295
296
297 NTSTATUS
298 STDCALL
299 NtQueryDebugFilterState(IN ULONG ComponentId,
300 IN ULONG Level)
301 {
302 unsigned int i;
303
304 /* convert Level to mask if it isn't already one */
305 if ( Level < 32 )
306 Level = 1 << Level;
307
308 for ( i = 0; i < KdComponentTableEntries; i++ )
309 {
310 if ( ComponentId == KdComponentTable[i].ComponentId )
311 {
312 if ( Level & KdComponentTable[i].Level )
313 return TRUE;
314 break;
315 }
316 }
317 return FALSE;
318 }
319
320 NTSTATUS
321 STDCALL
322 NtSetDebugFilterState(IN ULONG ComponentId,
323 IN ULONG Level,
324 IN BOOLEAN State)
325 {
326 unsigned int i;
327 for ( i = 0; i < KdComponentTableEntries; i++ )
328 {
329 if ( ComponentId == KdComponentTable[i].ComponentId )
330 break;
331 }
332 if ( i == KdComponentTableEntries )
333 {
334 if ( i == MAX_KD_COMPONENT_TABLE_ENTRIES )
335 return STATUS_INVALID_PARAMETER_1;
336 ++KdComponentTableEntries;
337 KdComponentTable[i].ComponentId = ComponentId;
338 KdComponentTable[i].Level = 0;
339 }
340
341 /* Convert level to mask, if needed */
342 if (Level < 32)
343 Level = 1 << Level;
344
345 if ( State )
346 KdComponentTable[i].Level |= Level;
347 else
348 KdComponentTable[i].Level &= ~Level;
349 return STATUS_SUCCESS;
350 }
351
352 /*
353 * @unimplemented
354 */
355 NTSTATUS
356 NTAPI
357 KdSystemDebugControl(IN SYSDBG_COMMAND Command,
358 IN PVOID InputBuffer,
359 IN ULONG InputBufferLength,
360 OUT PVOID OutputBuffer,
361 IN ULONG OutputBufferLength,
362 IN OUT PULONG ReturnLength,
363 IN KPROCESSOR_MODE PreviousMode)
364 {
365 /* HACK */
366 return KdpServiceDispatcher(Command, InputBuffer, InputBufferLength);
367 }
368
369 PKDEBUG_ROUTINE KiDebugRoutine = KdpEnterDebuggerException;
370
371 /* EOF */