[FREELDR]
[reactos.git] / reactos / boot / freeldr / freeldr / debug.c
1 /*
2 * FreeLoader
3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <freeldr.h>
21
22 #include <debug.h>
23
24 #if DBG && !defined(_M_ARM)
25
26 //#define DEBUG_ALL
27 //#define DEBUG_WARN
28 //#define DEBUG_ERR
29 //#define DEBUG_INIFILE
30 //#define DEBUG_REACTOS
31 //#define DEBUG_CUSTOM
32 #define DEBUG_NONE
33
34 #define DBG_DEFAULT_LEVELS (ERR_LEVEL|FIXME_LEVEL)
35
36 #define SCREEN 1
37 #define RS232 2
38 #define BOCHS 4
39
40 #define COM1 1
41 #define COM2 2
42 #define COM3 3
43 #define COM4 4
44
45 #define BOCHS_OUTPUT_PORT 0xe9
46
47
48 static UCHAR DbgChannels[DBG_CHANNELS_COUNT];
49
50 ULONG DebugPort = RS232;
51 //ULONG DebugPort = SCREEN;
52 //ULONG DebugPort = BOCHS;
53 //ULONG DebugPort = SCREEN|BOCHS;
54 #ifdef _WINKD_
55 /* COM1 is the WinDbg port */
56 ULONG ComPort = COM2;
57 #else
58 ULONG ComPort = COM1;
59 #endif
60 //ULONG BaudRate = 19200;
61 ULONG BaudRate = 115200;
62
63 BOOLEAN DebugStartOfLine = TRUE;
64
65 VOID DebugInit(VOID)
66 {
67 #if defined (DEBUG_ALL)
68 memset(DbgChannels, MAX_LEVEL, DBG_CHANNELS_COUNT);
69 #elif defined (DEBUG_WARN)
70 memset(DbgChannels, WARN_LEVEL|FIXME_LEVEL|ERR_LEVEL, DBG_CHANNELS_COUNT);
71 #elif defined (DEBUG_ERR)
72 memset(DbgChannels, ERR_LEVEL, DBG_CHANNELS_COUNT);
73 #else
74 memset(DbgChannels, 0, DBG_CHANNELS_COUNT);
75 #endif
76
77 #if defined (DEBUG_INIFILE)
78 DbgChannels[DPRINT_INIFILE] = MAX_LEVEL;
79 #elif defined (DEBUG_REACTOS)
80 DbgChannels[DPRINT_REACTOS] = MAX_LEVEL;
81 DbgChannels[DPRINT_REGISTRY] = MAX_LEVEL;
82 #elif defined (DEBUG_CUSTOM)
83 DbgChannels[DPRINT_WARNING] = MAX_LEVEL;
84 DbgChannels[DPRINT_WINDOWS] = MAX_LEVEL;
85 #endif
86
87 if (DebugPort & RS232)
88 {
89 Rs232PortInitialize(ComPort, BaudRate);
90 }
91 }
92
93 VOID DebugPrintChar(UCHAR Character)
94 {
95 if (Character == '\n')
96 {
97 DebugStartOfLine = TRUE;
98 }
99
100 if (DebugPort & RS232)
101 {
102 if (Character == '\n')
103 {
104 Rs232PortPutByte('\r');
105 }
106 Rs232PortPutByte(Character);
107 }
108 if (DebugPort & BOCHS)
109 {
110 WRITE_PORT_UCHAR((PUCHAR)BOCHS_OUTPUT_PORT, Character);
111 }
112 if (DebugPort & SCREEN)
113 {
114 MachConsPutChar(Character);
115 }
116 }
117
118 ULONG
119 DbgPrint(const char *Format, ...)
120 {
121 int i;
122 int Length;
123 va_list ap;
124 CHAR Buffer[512];
125
126 va_start(ap, Format);
127 Length = _vsnprintf(Buffer, sizeof(Buffer), Format, ap);
128 va_end(ap);
129
130 /* Check if we went past the buffer */
131 if (Length == -1)
132 {
133 /* Terminate it if we went over-board */
134 Buffer[sizeof(Buffer) - 1] = '\n';
135
136 /* Put maximum */
137 Length = sizeof(Buffer);
138 }
139
140 for (i = 0; i < Length; i++)
141 {
142 DebugPrintChar(Buffer[i]);
143 }
144
145 return 0;
146 }
147
148 VOID
149 DbgPrint2(ULONG Mask, ULONG Level, const char *File, ULONG Line, char *Format, ...)
150 {
151 va_list ap;
152 char Buffer[2096];
153 char *ptr = Buffer;
154
155 // Mask out unwanted debug messages
156 if (!(DbgChannels[Mask] & Level) && !(Level & DBG_DEFAULT_LEVELS ))
157 {
158 return;
159 }
160
161 // Print the header if we have started a new line
162 if (DebugStartOfLine)
163 {
164 DbgPrint("(%s:%lu) ", File, Line);
165
166 switch (Level)
167 {
168 case ERR_LEVEL:
169 DbgPrint("err: ");
170 break;
171 case FIXME_LEVEL:
172 DbgPrint("fixme: ");
173 break;
174 case WARN_LEVEL:
175 DbgPrint("warn: ");
176 break;
177 case TRACE_LEVEL:
178 DbgPrint("trace: ");
179 break;
180 }
181
182 DebugStartOfLine = FALSE;
183 }
184
185 va_start(ap, Format);
186 vsprintf(Buffer, Format, ap);
187 va_end(ap);
188
189 while (*ptr)
190 {
191 DebugPrintChar(*ptr++);
192 }
193 }
194
195 VOID
196 DebugDumpBuffer(ULONG Mask, PVOID Buffer, ULONG Length)
197 {
198 PUCHAR BufPtr = (PUCHAR)Buffer;
199 ULONG Idx;
200 ULONG Idx2;
201
202 // Mask out unwanted debug messages
203 if (!(DbgChannels[Mask] & TRACE_LEVEL))
204 {
205 return;
206 }
207
208 DebugStartOfLine = FALSE; // We don't want line headers
209 DbgPrint("Dumping buffer at %p with length of %lu bytes:\n", Buffer, Length);
210
211 for (Idx=0; Idx<Length; )
212 {
213 DebugStartOfLine = FALSE; // We don't want line headers
214
215 if (Idx < 0x0010)
216 {
217 DbgPrint("000%x:\t", Idx);
218 }
219 else if (Idx < 0x0100)
220 {
221 DbgPrint("00%x:\t", Idx);
222 }
223 else if (Idx < 0x1000)
224 {
225 DbgPrint("0%x:\t", Idx);
226 }
227 else
228 {
229 DbgPrint("%x:\t", Idx);
230 }
231
232 for (Idx2=0; Idx2<16; Idx2++,Idx++)
233 {
234 if (BufPtr[Idx] < 0x10)
235 {
236 DbgPrint("0");
237 }
238 DbgPrint("%x", BufPtr[Idx]);
239
240 if (Idx2 == 7)
241 {
242 DbgPrint("-");
243 }
244 else
245 {
246 DbgPrint(" ");
247 }
248 }
249
250 Idx -= 16;
251 DbgPrint(" ");
252
253 for (Idx2=0; Idx2<16; Idx2++,Idx++)
254 {
255 if ((BufPtr[Idx] > 20) && (BufPtr[Idx] < 0x80))
256 {
257 DbgPrint("%c", BufPtr[Idx]);
258 }
259 else
260 {
261 DbgPrint(".");
262 }
263 }
264
265 DbgPrint("\n");
266 }
267 }
268
269 static BOOLEAN
270 DbgAddDebugChannel( CHAR* channel, CHAR* level, CHAR op)
271 {
272 int iLevel, iChannel;
273
274 if(channel == NULL || *channel == L'\0' ||strlen(channel) == 0 )
275 return FALSE;
276
277 if(level == NULL || *level == L'\0' ||strlen(level) == 0 )
278 iLevel = MAX_LEVEL;
279 else if(strcmp(level, "err") == 0)
280 iLevel = ERR_LEVEL;
281 else if(strcmp(level, "fixme") == 0)
282 iLevel = FIXME_LEVEL;
283 else if(strcmp(level, "warn") == 0)
284 iLevel = WARN_LEVEL;
285 else if (strcmp(level, "trace") == 0)
286 iLevel = TRACE_LEVEL;
287 else
288 return FALSE;
289
290 if(strcmp(channel, "memory") == 0) iChannel = DPRINT_MEMORY;
291 else if(strcmp(channel, "filesystem") == 0) iChannel = DPRINT_FILESYSTEM;
292 else if(strcmp(channel, "inifile") == 0) iChannel = DPRINT_INIFILE;
293 else if(strcmp(channel, "ui") == 0) iChannel = DPRINT_UI;
294 else if(strcmp(channel, "disk") == 0) iChannel = DPRINT_DISK;
295 else if(strcmp(channel, "cache") == 0) iChannel = DPRINT_CACHE;
296 else if(strcmp(channel, "registry") == 0) iChannel = DPRINT_REGISTRY;
297 else if(strcmp(channel, "linux") == 0) iChannel = DPRINT_LINUX;
298 else if(strcmp(channel, "hwdetect") == 0) iChannel = DPRINT_HWDETECT;
299 else if(strcmp(channel, "windows") == 0) iChannel = DPRINT_WINDOWS;
300 else if(strcmp(channel, "peloader") == 0) iChannel = DPRINT_PELOADER;
301 else if(strcmp(channel, "scsiport") == 0) iChannel = DPRINT_SCSIPORT;
302 else if(strcmp(channel, "heap") == 0) iChannel = DPRINT_HEAP;
303 else if(strcmp(channel, "all") == 0)
304 {
305 int i;
306
307 for(i= 0 ; i < DBG_CHANNELS_COUNT; i++)
308 {
309 if(op==L'+')
310 DbgChannels[i] |= iLevel;
311 else
312 DbgChannels[i] &= ~iLevel;
313 }
314
315 return TRUE;
316 }
317 else return FALSE;
318
319 if(op==L'+')
320 DbgChannels[iChannel] |= iLevel;
321 else
322 DbgChannels[iChannel] &= ~iLevel;
323
324 return TRUE;
325 }
326
327 VOID
328 DbgParseDebugChannels(PCHAR Value)
329 {
330 CHAR *str, *separator, *c, op;
331
332 str = Value;
333
334 do
335 {
336 separator = strchr(str, L',');
337 if(separator != NULL)
338 *separator = L'\0';
339
340 c = strchr(str, L'+');
341 if(c == NULL)
342 c = strchr(str, L'-');
343
344 if(c != NULL)
345 {
346 op = *c;
347 *c = L'\0';
348 c++;
349
350 DbgAddDebugChannel(c, str, op);
351 }
352
353 str = separator + 1;
354 } while(separator != NULL);
355 }
356
357 #else
358
359 ULONG
360 DbgPrint(PCCH Format, ...)
361 {
362 return 0;
363 }
364
365 #endif // DBG
366
367 ULONG
368 MsgBoxPrint(const char *Format, ...)
369 {
370 va_list ap;
371 CHAR Buffer[512];
372 ULONG Length;
373
374 va_start(ap, Format);
375
376 /* Construct a string */
377 Length = _vsnprintf(Buffer, 512, Format, ap);
378
379 /* Check if we went past the buffer */
380 if (Length == MAXULONG)
381 {
382 /* Terminate it if we went over-board */
383 Buffer[sizeof(Buffer) - 1] = '\n';
384
385 /* Put maximum */
386 Length = sizeof(Buffer);
387 }
388
389 /* Show it as a message box */
390 UiMessageBox(Buffer);
391
392 /* Cleanup and exit */
393 va_end(ap);
394 return 0;
395 }
396
397 //DECLSPEC_NORETURN
398 VOID
399 NTAPI
400 KeBugCheckEx(
401 IN ULONG BugCheckCode,
402 IN ULONG_PTR BugCheckParameter1,
403 IN ULONG_PTR BugCheckParameter2,
404 IN ULONG_PTR BugCheckParameter3,
405 IN ULONG_PTR BugCheckParameter4)
406 {
407 char Buffer[70];
408 sprintf(Buffer, "*** STOP: 0x%08lX (0x%08lX, 0x%08lX, 0x%08lX, 0x%08lX)",
409 BugCheckCode, BugCheckParameter1, BugCheckParameter2,
410 BugCheckParameter3, BugCheckParameter4);
411 UiMessageBoxCritical(Buffer);
412 assert(FALSE);
413 for (;;);
414 }
415
416 VOID
417 NTAPI
418 RtlAssert(IN PVOID FailedAssertion,
419 IN PVOID FileName,
420 IN ULONG LineNumber,
421 IN PCHAR Message OPTIONAL)
422 {
423 if (Message)
424 {
425 DbgPrint("Assertion \'%s\' failed at %s line %u: %s\n",
426 (PCHAR)FailedAssertion,
427 (PCHAR)FileName,
428 LineNumber,
429 Message);
430 }
431 else
432 {
433 DbgPrint("Assertion \'%s\' failed at %s line %u\n",
434 (PCHAR)FailedAssertion,
435 (PCHAR)FileName,
436 LineNumber);
437 }
438
439 DbgBreakPoint();
440 }
441
442 char *BugCodeStrings[] =
443 {
444 "TEST_BUGCHECK",
445 "MISSING_HARDWARE_REQUIREMENTS",
446 "FREELDR_IMAGE_CORRUPTION",
447 "MEMORY_INIT_FAILURE",
448 };
449
450 ULONG_PTR BugCheckInfo[5];
451