implement DbgPrintEx, vDbgPrintEx, and vDbgPrintExWithPrefix
[reactos.git] / reactos / ntoskrnl / rtl / debug.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/rtl/dbgprint.c
5 * PURPOSE: Debug output
6 *
7 * PROGRAMMERS: Eric Kohl (ekohl@abo.rhein-zeitung.de)
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntoskrnl.h>
13 #include <internal/debug.h>
14
15 /* DATA *********************************************************************/
16
17 typedef struct
18 {
19 ULONG ComponentId;
20 ULONG Level;
21 } KD_COMPONENT_DATA;
22 #define MAX_KD_COMPONENT_TABLE_ENTRIES 128
23 KD_COMPONENT_DATA KdComponentTable[MAX_KD_COMPONENT_TABLE_ENTRIES];
24 ULONG KdComponentTableEntries = 0;
25
26 /* FUNCTIONS ****************************************************************/
27
28 /*
29 * Note: DON'T CHANGE THIS FUNCTION!!!
30 * DON'T CALL HalDisplayString OR SOMETING ELSE!!!
31 * You'll only break the serial/bochs debugging feature!!!
32 */
33
34 /*
35 * @implemented
36 */
37 ULONG WINAPI
38 vDbgPrintExWithPrefix(IN LPCSTR Prefix,
39 IN ULONG ComponentId,
40 IN ULONG Level,
41 IN LPCSTR Format,
42 IN va_list ap)
43 {
44 ANSI_STRING DebugString;
45 CHAR Buffer[513];
46 PCHAR pBuffer;
47 ULONG pBufferSize;
48 #ifdef SERIALIZE_DBGPRINT
49 # define MESSAGETABLE_SIZE 16
50 LONG MyTableIndex;
51 static LONG Lock = 0;
52 static LONG TableWriteIndex = 0, TableReadIndex = 0;
53 static CHAR MessageTable[MESSAGETABLE_SIZE][sizeof(Buffer)] = { { '\0' } };
54 #endif /* SERIALIZE_DBGPRINT */
55
56 /* TODO FIXME - call NtQueryDebugFilterState() instead per Alex */
57 if ( !DbgQueryDebugFilterState ( ComponentId, Level ) )
58 return 0;
59
60 /* init ansi string */
61 DebugString.Buffer = Buffer;
62 DebugString.MaximumLength = sizeof(Buffer);
63
64 pBuffer = Buffer;
65 pBufferSize = sizeof(Buffer);
66 DebugString.Length = 0;
67 if ( Prefix && *Prefix )
68 {
69 DebugString.Length = strlen(Prefix);
70 if ( DebugString.Length >= sizeof(Buffer) )
71 DebugString.Length = sizeof(Buffer) - 1;
72 memmove ( Buffer, Prefix, DebugString.Length );
73 Buffer[DebugString.Length] = '\0';
74 pBuffer = &Buffer[DebugString.Length];
75 pBufferSize -= DebugString.Length;
76 }
77
78 DebugString.Length += _vsnprintf ( pBuffer, pBufferSize, Format, ap );
79 Buffer[sizeof(Buffer)-1] = '\0';
80
81 #ifdef SERIALIZE_DBGPRINT
82 /* check if we are already running */
83 if (InterlockedCompareExchange(&Lock, 1, 0) == 1)
84 {
85 MyTableIndex = InterlockedIncrement(&TableWriteIndex) - 1;
86 InterlockedCompareExchange(&TableWriteIndex, 0, MESSAGETABLE_SIZE);
87 MyTableIndex %= MESSAGETABLE_SIZE;
88
89 if (MessageTable[MyTableIndex][0] != '\0') /* table is full */
90 {
91 DebugString.Buffer = "CRITICAL ERROR: DbgPrint Table is FULL!";
92 DebugString.Length = 39;
93 KdpPrintString(&DebugString);
94 for (;;);
95 }
96 else
97 {
98 memcpy(MessageTable[MyTableIndex], DebugString.Buffer, DebugString.Length);
99 MessageTable[MyTableIndex][DebugString.Length] = '\0';
100 }
101 }
102 else
103 {
104 #endif /* SERIALIZE_DBGPRINT */
105 KdpPrintString (&DebugString);
106 #ifdef SERIALIZE_DBGPRINT
107 MyTableIndex = TableReadIndex;
108 while (MessageTable[MyTableIndex][0] != '\0')
109 {
110 /*DebugString.Buffer = "$$$";
111 DebugString.Length = 3;
112 KdpPrintString(&DebugString);*/
113
114 DebugString.Buffer = MessageTable[MyTableIndex];
115 DebugString.Length = strlen(DebugString.Buffer);
116 DebugString.MaximumLength = DebugString.Length + 1;
117
118 KdpPrintString(&DebugString);
119 MessageTable[MyTableIndex][0] = '\0';
120
121 MyTableIndex = InterlockedIncrement(&TableReadIndex);
122 InterlockedCompareExchange(&TableReadIndex, 0, MESSAGETABLE_SIZE);
123 MyTableIndex %= MESSAGETABLE_SIZE;
124 }
125 InterlockedDecrement(&Lock);
126 }
127 # undef MESSAGETABLE_SIZE
128 #endif /* SERIALIZE_DBGPRINT */
129
130 return (ULONG)DebugString.Length;
131 }
132
133 /*
134 * @implemented
135 */
136 ULONG WINAPI
137 vDbgPrintEx(IN ULONG ComponentId,
138 IN ULONG Level,
139 IN LPCSTR Format,
140 IN va_list ap)
141 {
142 return vDbgPrintExWithPrefix ( NULL, ComponentId, Level, Format, ap );
143 }
144
145 /*
146 * @implemented
147 */
148 ULONG
149 DbgPrint(PCH Format, ...)
150 {
151 va_list ap;
152 ULONG rc;
153
154 va_start (ap, Format);
155 /* TODO FIXME - use DPFLTR_DEFAULT_ID and DPFLTR_INFO_LEVEL
156 *
157 * https://www.osronline.com/article.cfm?article=295
158 *
159 * ( first need to add those items to registry by default tho so we don't anger
160 * ros-devs when DbgPrint() suddenly stops working )
161 *
162 * ( also when you do this, remove -1 hack from DbgQueryDebugFilterState() )
163 */
164 rc = vDbgPrintExWithPrefix ( NULL, (ULONG)-1, (ULONG)-1, Format, ap );
165 va_end (ap);
166
167 return rc;
168 }
169
170 /*
171 * @implemented
172 */
173 ULONG
174 __cdecl
175 DbgPrintEx(IN ULONG ComponentId,
176 IN ULONG Level,
177 IN PCH Format,
178 ...)
179 {
180 va_list ap;
181 ULONG rc;
182
183 va_start (ap, Format);
184 rc = vDbgPrintExWithPrefix ( NULL, ComponentId, Level, Format, ap );
185 va_end (ap);
186
187 return rc;
188 }
189
190 /*
191 * @unimplemented
192 */
193 ULONG
194 __cdecl
195 DbgPrintReturnControlC(PCH Format,
196 ...)
197 {
198 UNIMPLEMENTED;
199 return 0;
200 }
201
202 /*
203 * @unimplemented
204 */
205 VOID
206 STDCALL
207 DbgPrompt(PCH OutputString,
208 PCH InputString,
209 USHORT InputSize)
210 {
211 ANSI_STRING Output;
212 ANSI_STRING Input;
213
214 Input.Length = 0;
215 Input.MaximumLength = InputSize;
216 Input.Buffer = InputString;
217
218 Output.Length = strlen (OutputString);
219 Output.MaximumLength = Output.Length + 1;
220 Output.Buffer = OutputString;
221
222 /* FIXME: Not implemented yet!
223 KdpPromptString (&Output, &Input); */
224 }
225
226 /*
227 * @implemented
228 */
229 BOOLEAN
230 STDCALL
231 DbgQueryDebugFilterState(IN ULONG ComponentId,
232 IN ULONG Level)
233 {
234 int i;
235
236 if ( ComponentId == -1 )
237 return TRUE;
238
239 /* convert Level to mask if it isn't already one */
240 if ( Level < 32 )
241 Level = 1 << Level;
242
243 for ( i = 0; i < KdComponentTableEntries; i++ )
244 {
245 if ( ComponentId == KdComponentTable[i].ComponentId )
246 {
247 if ( Level & KdComponentTable[i].Level )
248 return TRUE;
249 break;
250 }
251 }
252 return FALSE;
253 }
254
255 /*
256 * @implemented
257 */
258 NTSTATUS
259 STDCALL
260 DbgSetDebugFilterState(IN ULONG ComponentId,
261 IN ULONG Level,
262 IN BOOLEAN State)
263 {
264 int i;
265 for ( i = 0; i < KdComponentTableEntries; i++ )
266 {
267 if ( ComponentId == KdComponentTable[i].ComponentId )
268 break;
269 }
270 if ( i == KdComponentTableEntries )
271 {
272 if ( i == MAX_KD_COMPONENT_TABLE_ENTRIES )
273 return STATUS_INVALID_PARAMETER_1;
274 ++KdComponentTableEntries;
275 KdComponentTable[i].ComponentId = ComponentId;
276 KdComponentTable[i].Level = 0;
277 }
278 if ( State )
279 KdComponentTable[i].Level |= Level;
280 else
281 KdComponentTable[i].Level &= ~Level;
282 return STATUS_SUCCESS;
283 }
284
285 /*
286 * @unimplemented
287 */
288 NTSTATUS
289 STDCALL
290 DbgLoadImageSymbols(IN PUNICODE_STRING Name,
291 IN ULONG Base,
292 IN ULONG Unknown3)
293 {
294 UNIMPLEMENTED;
295 return STATUS_NOT_IMPLEMENTED;
296 }
297 /* EOF */