Merge branch 'master' of cadel.mutabah.net:acess2
[tpg/acess2.git] / KernelLand / Kernel / debug.c
1 /*
2  * AcessOS Microkernel Version
3  * debug.c
4  */
5 #include <acess.h>
6 #include <stdarg.h>
7
8 #define DEBUG_MAX_LINE_LEN      256
9 #define LOCK_DEBUG_OUTPUT       1       // Avoid interleaving of output lines?
10 #define TRACE_TO_KTERM  0       // Send ENTER/DEBUG/LEAVE to debug?
11
12 // === IMPORTS ===
13 extern void     Threads_Dump(void);
14 extern void     KernelPanic_SetMode(void);
15 extern void     KernelPanic_PutChar(char Ch);
16
17 // === PROTOTYPES ===
18 static void     Debug_Putchar(char ch);
19 static void     Debug_Puts(int bUseKTerm, const char *Str);
20 void    Debug_DbgOnlyFmt(const char *format, va_list args);
21 void    Debug_FmtS(int bUseKTerm, const char *format, ...);
22 void    Debug_Fmt(int bUseKTerm, const char *format, va_list args);
23 void    Debug_SetKTerminal(const char *File);
24
25 // === GLOBALS ===
26  int    gDebug_Level = 0;
27  int    giDebug_KTerm = -1;
28  int    gbDebug_IsKPanic = 0;
29 volatile int    gbInPutChar = 0;
30 #if LOCK_DEBUG_OUTPUT
31 tShortSpinlock  glDebug_Lock;
32 #endif
33
34 // === CODE ===
35 static void Debug_Putchar(char ch)
36 {
37         Debug_PutCharDebug(ch);
38         if( !gbDebug_IsKPanic )
39         {
40                 if(gbInPutChar) return ;
41                 gbInPutChar = 1;
42                 if(giDebug_KTerm != -1)
43                         VFS_Write(giDebug_KTerm, 1, &ch);
44                 gbInPutChar = 0;
45         }
46         else
47                 KernelPanic_PutChar(ch);
48 }
49
50 static void Debug_Puts(int UseKTerm, const char *Str)
51 {
52          int    len = 0;
53         
54         Debug_PutStringDebug(Str);
55         
56         if( gbDebug_IsKPanic )
57         {               
58                 for( len = 0; Str[len]; len ++ )
59                         KernelPanic_PutChar( Str[len] );
60         }
61         else
62                 for( len = 0; Str[len]; len ++ );
63         
64         // Output to the kernel terminal
65         if( UseKTerm && !gbDebug_IsKPanic && giDebug_KTerm != -1)
66         {
67                 if(gbInPutChar) return ;
68                 gbInPutChar = 1;
69                 VFS_Write(giDebug_KTerm, len, Str);
70                 gbInPutChar = 0;
71         }
72 }
73
74 void Debug_DbgOnlyFmt(const char *format, va_list args)
75 {
76         Debug_Fmt(0, format, args);
77 }
78
79 void Debug_Fmt(int bUseKTerm, const char *format, va_list args)
80 {
81         char    buf[DEBUG_MAX_LINE_LEN];
82          int    len;
83         buf[DEBUG_MAX_LINE_LEN-1] = 0;
84         len = vsnprintf(buf, DEBUG_MAX_LINE_LEN-1, format, args);
85         //if( len < DEBUG_MAX_LINE )
86                 // do something
87         Debug_Puts(bUseKTerm, buf);
88         return ;
89 }
90
91 void Debug_FmtS(int bUseKTerm, const char *format, ...)
92 {
93         va_list args;   
94         va_start(args, format);
95         Debug_Fmt(bUseKTerm, format, args);
96         va_end(args);
97 }
98
99 void Debug_KernelPanic(void)
100 {
101         #if LOCK_DEBUG_OUTPUT
102         SHORTREL(&glDebug_Lock);
103         #endif
104         gbDebug_IsKPanic = 1;
105         KernelPanic_SetMode();
106 }
107
108 /**
109  * \fn void LogF(const char *Msg, ...)
110  * \brief Raw debug log (no new line, no prefix)
111  */
112 void LogF(const char *Fmt, ...)
113 {
114         va_list args;
115
116         #if LOCK_DEBUG_OUTPUT
117         SHORTLOCK(&glDebug_Lock);
118         #endif
119         
120         va_start(args, Fmt);
121
122         Debug_Fmt(1, Fmt, args);
123
124         va_end(args);
125         
126         #if LOCK_DEBUG_OUTPUT
127         SHORTREL(&glDebug_Lock);
128         #endif
129 }
130 /**
131  * \fn void Debug(const char *Msg, ...)
132  * \brief Print only to the debug channel (not KTerm)
133  */
134 void Debug(const char *Fmt, ...)
135 {
136         va_list args;
137         
138         #if LOCK_DEBUG_OUTPUT
139         SHORTLOCK(&glDebug_Lock);
140         #endif
141
142         Debug_Puts(0, "Debug: ");
143         va_start(args, Fmt);
144         Debug_DbgOnlyFmt(Fmt, args);
145         va_end(args);
146         Debug_PutCharDebug('\r');
147         Debug_PutCharDebug('\n');
148         #if LOCK_DEBUG_OUTPUT
149         SHORTREL(&glDebug_Lock);
150         #endif
151 }
152 /**
153  * \fn void Log(const char *Msg, ...)
154  */
155 void Log(const char *Fmt, ...)
156 {
157         va_list args;
158         
159         #if LOCK_DEBUG_OUTPUT
160         SHORTLOCK(&glDebug_Lock);
161         #endif
162
163         Debug_Puts(1, "Log: ");
164         va_start(args, Fmt);
165         Debug_Fmt(1, Fmt, args);
166         va_end(args);
167         Debug_Puts(1, "\r\n");
168         
169         #if LOCK_DEBUG_OUTPUT
170         SHORTREL(&glDebug_Lock);
171         #endif
172 }
173 void Warning(const char *Fmt, ...)
174 {
175         va_list args;
176         
177         #if LOCK_DEBUG_OUTPUT
178         SHORTLOCK(&glDebug_Lock);
179         #endif
180         
181         Debug_Puts(1, "Warning: ");
182         va_start(args, Fmt);
183         Debug_Fmt(1, Fmt, args);
184         va_end(args);
185         Debug_Putchar('\r');
186         Debug_Putchar('\n');
187         
188         #if LOCK_DEBUG_OUTPUT
189         SHORTREL(&glDebug_Lock);
190         #endif
191 }
192 void Panic(const char *Fmt, ...)
193 {
194         va_list args;
195         
196         #if LOCK_DEBUG_OUTPUT
197         SHORTLOCK(&glDebug_Lock);
198         #endif
199         // And never SHORTREL
200         
201         Debug_KernelPanic();
202         
203         Debug_Puts(1, "Panic: ");
204         va_start(args, Fmt);
205         Debug_Fmt(1, Fmt, args);
206         va_end(args);
207         Debug_Putchar('\r');
208         Debug_Putchar('\n');
209
210         Threads_Dump();
211
212         for(;;) ;
213 }
214
215 void Debug_SetKTerminal(const char *File)
216 {
217          int    tmp;
218         if(giDebug_KTerm != -1) {
219                 tmp = giDebug_KTerm;
220                 giDebug_KTerm = -1;
221                 VFS_Close(tmp);
222         }
223         tmp = VFS_Open(File, VFS_OPENFLAG_WRITE);
224 //      Log_Log("Debug", "Opened '%s' as 0x%x", File, tmp);
225         giDebug_KTerm = tmp;
226 //      Log_Log("Debug", "Returning to %p", __builtin_return_address(0));
227 }
228
229 void Debug_Enter(const char *FuncName, const char *ArgTypes, ...)
230 {
231         va_list args;
232          int    i;
233          int    pos;
234         tTID    tid = Threads_GetTID();
235          
236         #if LOCK_DEBUG_OUTPUT
237         SHORTLOCK(&glDebug_Lock);
238         #endif
239
240         i = gDebug_Level ++;
241
242         va_start(args, ArgTypes);
243
244         Debug_FmtS(TRACE_TO_KTERM, "%014lli ", now());
245         while(i--)      Debug_Puts(TRACE_TO_KTERM, " ");
246
247         Debug_Puts(TRACE_TO_KTERM, FuncName);
248         Debug_FmtS(TRACE_TO_KTERM, "[%i]", tid);
249         Debug_Puts(TRACE_TO_KTERM, ": (");
250
251         while(*ArgTypes)
252         {
253                 pos = strpos(ArgTypes, ' ');
254                 if(pos == -1 || pos > 1) {
255                         if(pos == -1)
256                                 Debug_Puts(TRACE_TO_KTERM, ArgTypes+1);
257                         else {
258                                 Debug_FmtS(TRACE_TO_KTERM, "%.*s", pos-1, ArgTypes+1);
259                         }
260                         Debug_Puts(TRACE_TO_KTERM, "=");
261                 }
262                 switch(*ArgTypes)
263                 {
264                 case 'p':       Debug_FmtS(TRACE_TO_KTERM, "%p", va_arg(args, void*));  break;
265                 case 'P':       Debug_FmtS(TRACE_TO_KTERM, "%P", va_arg(args, tPAddr)); break;
266                 case 's':       Debug_FmtS(TRACE_TO_KTERM, "'%s'", va_arg(args, char*));        break;
267                 case 'i':       Debug_FmtS(TRACE_TO_KTERM, "%i", va_arg(args, int));    break;
268                 case 'u':       Debug_FmtS(TRACE_TO_KTERM, "%u", va_arg(args, Uint));   break;
269                 case 'x':       Debug_FmtS(TRACE_TO_KTERM, "0x%x", va_arg(args, Uint)); break;
270                 case 'b':       Debug_FmtS(TRACE_TO_KTERM, "0b%b", va_arg(args, Uint)); break;
271                 case 'X':       Debug_FmtS(TRACE_TO_KTERM, "0x%llx", va_arg(args, Uint64));     break;  // Extended (64-Bit)
272                 case 'B':       Debug_FmtS(TRACE_TO_KTERM, "0b%llb", va_arg(args, Uint64));     break;  // Extended (64-Bit)
273                 }
274                 if(pos != -1) {
275                         Debug_Puts(TRACE_TO_KTERM, ", ");
276                 }
277
278                 if(pos == -1)   break;
279                 ArgTypes = &ArgTypes[pos+1];
280         }
281
282         va_end(args);
283         Debug_Puts(TRACE_TO_KTERM, ")\r\n");
284         
285         #if LOCK_DEBUG_OUTPUT
286         SHORTREL(&glDebug_Lock);
287         #endif
288 }
289
290 void Debug_Log(const char *FuncName, const char *Fmt, ...)
291 {
292         va_list args;
293          int    i = gDebug_Level;
294         tTID    tid = Threads_GetTID();
295
296         #if LOCK_DEBUG_OUTPUT
297         SHORTLOCK(&glDebug_Lock);
298         #endif
299
300         Debug_FmtS(TRACE_TO_KTERM, "%014lli ", now());
301         while(i--)      Debug_Puts(TRACE_TO_KTERM, " ");
302
303         Debug_Puts(TRACE_TO_KTERM, FuncName);
304         Debug_FmtS(TRACE_TO_KTERM, "[%i]", tid);
305         Debug_Puts(TRACE_TO_KTERM, ": ");
306
307         va_start(args, Fmt);
308         Debug_Fmt(TRACE_TO_KTERM, Fmt, args);
309         va_end(args);
310
311         Debug_Puts(TRACE_TO_KTERM, "\r\n");
312         
313         #if LOCK_DEBUG_OUTPUT
314         SHORTREL(&glDebug_Lock);
315         #endif
316 }
317
318 void Debug_Leave(const char *FuncName, char RetType, ...)
319 {
320         va_list args;
321          int    i;
322         tTID    tid = Threads_GetTID();
323
324         #if LOCK_DEBUG_OUTPUT
325         SHORTLOCK(&glDebug_Lock);
326         #endif
327         
328         i = --gDebug_Level;
329
330         va_start(args, RetType);
331
332         if( i == -1 ) {
333                 gDebug_Level = 0;
334                 i = 0;
335         }
336         Debug_FmtS(TRACE_TO_KTERM, "%014lli ", now());
337         // Indenting
338         while(i--)      Debug_Puts(TRACE_TO_KTERM, " ");
339
340         Debug_Puts(TRACE_TO_KTERM, FuncName);
341         Debug_FmtS(TRACE_TO_KTERM, "[%i]", tid);
342         Debug_Puts(TRACE_TO_KTERM, ": RETURN");
343
344         // No Return
345         if(RetType == '-') {
346                 Debug_Puts(TRACE_TO_KTERM, "\r\n");
347                 #if LOCK_DEBUG_OUTPUT
348                 SHORTREL(&glDebug_Lock);
349                 #endif
350                 return;
351         }
352
353         switch(RetType)
354         {
355         case 'n':       Debug_Puts(TRACE_TO_KTERM, " NULL");    break;
356         case 'p':       Debug_Fmt(TRACE_TO_KTERM, " %p", args); break;
357         case 'P':       Debug_Fmt(TRACE_TO_KTERM, " %P", args); break;  // PAddr
358         case 's':       Debug_Fmt(TRACE_TO_KTERM, " '%s'", args);       break;
359         case 'i':       Debug_Fmt(TRACE_TO_KTERM, " %i", args); break;
360         case 'u':       Debug_Fmt(TRACE_TO_KTERM, " %u", args); break;
361         case 'x':       Debug_Fmt(TRACE_TO_KTERM, " 0x%x", args);       break;
362         // Extended (64-Bit)
363         case 'X':       Debug_Fmt(TRACE_TO_KTERM, " 0x%llx", args);     break;
364         }
365         Debug_Puts(TRACE_TO_KTERM, "\r\n");
366
367         va_end(args);
368         
369         #if LOCK_DEBUG_OUTPUT
370         SHORTREL(&glDebug_Lock);
371         #endif
372 }
373
374 void Debug_HexDump(const char *Header, const void *Data, Uint Length)
375 {
376         const Uint8     *cdat = Data;
377         Uint    pos = 0;
378         LogF("%014lli ", now());
379         Debug_Puts(1, Header);
380         LogF(" (Hexdump of %p)\r\n", Data);
381
382         #define CH(n)   ((' '<=cdat[(n)]&&cdat[(n)]<0x7F) ? cdat[(n)] : '.')
383
384         while(Length >= 16)
385         {
386                 LogF("%014lli Log: %04x:"
387                         " %02x %02x %02x %02x %02x %02x %02x %02x"
388                         " %02x %02x %02x %02x %02x %02x %02x %02x"
389                         "  %c%c%c%c%c%c%c%c %c%c%c%c%c%c%c%c\r\n",
390                         now(),
391                         pos,
392                         cdat[ 0], cdat[ 1], cdat[ 2], cdat[ 3], cdat[ 4], cdat[ 5], cdat[ 6], cdat[ 7],
393                         cdat[ 8], cdat[ 9], cdat[10], cdat[11], cdat[12], cdat[13], cdat[14], cdat[15],
394                         CH(0),  CH(1),  CH(2),  CH(3),  CH(4),  CH(5),  CH(6),  CH(7),
395                         CH(8),  CH(9),  CH(10), CH(11), CH(12), CH(13), CH(14), CH(15)
396                         );
397                 Length -= 16;
398                 cdat += 16;
399                 pos += 16;
400         }
401
402         {
403                  int    i ;
404                 LogF("%014lli Log: %04x: ", now(), pos);
405                 for(i = 0; i < Length; i ++)
406                 {
407                         LogF("%02x ", cdat[i]);
408                 }
409                 for( ; i < 16; i ++)    LogF("   ");
410                 LogF(" ");
411                 for(i = 0; i < Length; i ++)
412                 {
413                         if( i == 8 )    LogF(" ");
414                         LogF("%c", CH(i));
415                 }
416         
417                 Debug_Putchar('\r');
418                 Debug_Putchar('\n');
419         }
420 }
421
422 // --- EXPORTS ---
423 EXPORT(Debug);
424 EXPORT(Log);
425 EXPORT(Warning);
426 EXPORT(Debug_Enter);
427 EXPORT(Debug_Log);
428 EXPORT(Debug_Leave);

UCC git Repository :: git.ucc.asn.au