- Stub NtSystemDebugControl.
[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
112 /* Check if this was a breakpoint due to DbgPrint or Load/UnloadSymbols */
113 if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) &&
114 (ExceptionRecord->NumberParameters > 0) &&
115 ((ExceptionCommand == BREAKPOINT_LOAD_SYMBOLS) ||
116 (ExceptionCommand == BREAKPOINT_UNLOAD_SYMBOLS) ||
117 (ExceptionCommand == BREAKPOINT_COMMAND_STRING) ||
118 (ExceptionCommand == BREAKPOINT_PRINT)))
119 {
120 /* Check if this is a debug print */
121 if (ExceptionCommand == BREAKPOINT_PRINT)
122 {
123 /* Print the string */
124 KdpServiceDispatcher(BREAKPOINT_PRINT,
125 (PVOID)ExceptionRecord->ExceptionInformation[1],
126 ExceptionRecord->ExceptionInformation[2]);
127 }
128
129 /* This we can handle: simply bump EIP */
130 Context->Eip++;
131 return TRUE;
132 }
133
134 /* Get out of here if the Debugger isn't connected */
135 if (KdDebuggerNotPresent) return FALSE;
136
137 /* Call KDBG if available */
138 Return = KdbEnterDebuggerException(ExceptionRecord,
139 PreviousMode,
140 Context,
141 TrapFrame,
142 !SecondChance);
143
144 /* Convert return to BOOLEAN */
145 if (Return == kdContinue) return TRUE;
146 return FALSE;
147 }
148
149 BOOLEAN
150 NTAPI
151 KdpCallGdb(IN PKTRAP_FRAME TrapFrame,
152 IN PEXCEPTION_RECORD ExceptionRecord,
153 IN PCONTEXT Context)
154 {
155 KD_CONTINUE_TYPE Return = kdDoNotHandleException;
156
157 /* Get out of here if the Debugger isn't connected */
158 if (KdDebuggerNotPresent) return FALSE;
159
160 /* FIXME:
161 * Right now, the GDB wrapper seems to handle exceptions differntly
162 * from KDGB and both are called at different times, while the GDB
163 * one is only called once and that's it. I don't really have the knowledge
164 * to fix the GDB stub, so until then, we'll be using this hack
165 */
166 if (WrapperInitRoutine)
167 {
168 Return = WrapperTable.KdpExceptionRoutine(ExceptionRecord,
169 Context,
170 TrapFrame);
171 }
172
173 /* Convert return to BOOLEAN */
174 if (Return == kdContinue) return TRUE;
175 return FALSE;
176 }
177
178 /* PUBLIC FUNCTIONS *********************************************************/
179
180 /*
181 * @implemented
182 */
183 NTSTATUS
184 STDCALL
185 KdDisableDebugger(VOID)
186 {
187 KIRQL OldIrql;
188
189 /* Raise IRQL */
190 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
191
192 /* TODO: Disable any breakpoints */
193
194 /* Disable the Debugger */
195 KdDebuggerEnabled = FALSE;
196
197 /* Lower the IRQL */
198 KeLowerIrql(OldIrql);
199
200 /* Return success */
201 return STATUS_SUCCESS;
202 }
203
204 /*
205 * @implemented
206 */
207 NTSTATUS
208 STDCALL
209 KdEnableDebugger(VOID)
210 {
211 KIRQL OldIrql;
212
213 /* Raise IRQL */
214 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
215
216 /* TODO: Re-enable any breakpoints */
217
218 /* Enable the Debugger */
219 KdDebuggerEnabled = TRUE;
220
221 /* Lower the IRQL */
222 KeLowerIrql(OldIrql);
223
224 /* Return success */
225 return STATUS_SUCCESS;
226 }
227
228 /*
229 * @implemented
230 */
231 BOOLEAN
232 STDCALL
233 KdPollBreakIn(VOID)
234 {
235 return KdpBreakPending;
236 }
237
238 /*
239 * @unimplemented
240 */
241 NTSTATUS
242 STDCALL
243 KdPowerTransition(ULONG PowerState)
244 {
245 UNIMPLEMENTED;
246 return STATUS_NOT_IMPLEMENTED;
247 }
248
249 /*
250 * @unimplemented
251 */
252 NTSTATUS
253 NTAPI
254 KdChangeOption(IN KD_OPTION Option,
255 IN ULONG InBufferLength OPTIONAL,
256 IN PVOID InBuffer,
257 IN ULONG OutBufferLength OPTIONAL,
258 OUT PVOID OutBuffer,
259 OUT PULONG OutBufferRequiredLength OPTIONAL)
260 {
261 UNIMPLEMENTED;
262 return STATUS_NOT_IMPLEMENTED;
263 }
264
265
266 NTSTATUS
267 STDCALL
268 NtQueryDebugFilterState(IN ULONG ComponentId,
269 IN ULONG Level)
270 {
271 unsigned int i;
272
273 /* convert Level to mask if it isn't already one */
274 if ( Level < 32 )
275 Level = 1 << Level;
276
277 for ( i = 0; i < KdComponentTableEntries; i++ )
278 {
279 if ( ComponentId == KdComponentTable[i].ComponentId )
280 {
281 if ( Level & KdComponentTable[i].Level )
282 return TRUE;
283 break;
284 }
285 }
286 return FALSE;
287 }
288
289 NTSTATUS
290 STDCALL
291 NtSetDebugFilterState(IN ULONG ComponentId,
292 IN ULONG Level,
293 IN BOOLEAN State)
294 {
295 unsigned int i;
296 for ( i = 0; i < KdComponentTableEntries; i++ )
297 {
298 if ( ComponentId == KdComponentTable[i].ComponentId )
299 break;
300 }
301 if ( i == KdComponentTableEntries )
302 {
303 if ( i == MAX_KD_COMPONENT_TABLE_ENTRIES )
304 return STATUS_INVALID_PARAMETER_1;
305 ++KdComponentTableEntries;
306 KdComponentTable[i].ComponentId = ComponentId;
307 KdComponentTable[i].Level = 0;
308 }
309 if ( State )
310 KdComponentTable[i].Level |= Level;
311 else
312 KdComponentTable[i].Level &= ~Level;
313 return STATUS_SUCCESS;
314 }
315
316 /*
317 * @unimplemented
318 */
319 NTSTATUS
320 NTAPI
321 KdSystemDebugControl(IN SYSDBG_COMMAND Command,
322 IN PVOID InputBuffer,
323 IN ULONG InputBufferLength,
324 OUT PVOID OutputBuffer,
325 IN ULONG OutputBufferLength,
326 IN OUT PULONG ReturnLength,
327 IN KPROCESSOR_MODE PreviousMode)
328 {
329 /* HACK */
330 return KdpServiceDispatcher(Command, InputBuffer, InputBufferLength);
331 }
332
333 PKDEBUG_ROUTINE KiDebugRoutine = KdpEnterDebuggerException;
334
335 /* EOF */