Flush serial device on panic.
[pintos-anon] / src / lib / debug.c
1 #include <debug.h>
2 #include <stdarg.h>
3 #include <stdbool.h>
4 #include <stddef.h>
5 #include <stdio.h>
6 #include <string.h>
7 #ifdef KERNEL
8 #include "threads/interrupt.h"
9 #include "devices/serial.h"
10 #else
11 #include <syscall.h>
12 #endif
13
14 #define MAX_CLASSES 16
15 static bool all_enabled;
16 static const char *enabled_classes[MAX_CLASSES];
17 static size_t enabled_cnt;
18
19 static bool class_is_enabled (const char *class);
20
21 /* Enables the debug message classes specified in CLASSES.  The
22    string CLASSES is modified by and becomes owned by this
23    function. */
24 void
25 debug_enable (char *classes) 
26 {
27   char *class, *save;
28
29   for (class = strtok_r (classes, ",", &save); class != NULL;
30        class = strtok_r (NULL, ",", &save))
31     {
32       if (strcmp (class, "all") && enabled_cnt < MAX_CLASSES)
33         enabled_classes[enabled_cnt++] = class;
34       else
35         all_enabled = true;
36     }
37 }
38
39 /* Prints a debug message along with the source file name, line
40    number, and function name of where it was emitted.  CLASS is
41    used to filter out unwanted messages. */
42 void
43 debug_message (const char *file, int line, const char *function,
44                const char *class, const char *message, ...) 
45 {
46   if (class_is_enabled (class)) 
47     {
48       va_list args;
49
50 #ifdef KERNEL
51       enum intr_level old_level = intr_disable ();
52 #endif
53       printf ("%s:%d: %s(): ", file, line, function);
54       va_start (args, message);
55       vprintf (message, args);
56       printf ("\n");
57       va_end (args);
58 #ifdef KERNEL
59       intr_set_level (old_level);
60 #endif
61     }
62 }
63
64 /* Halts the OS, printing the source file name, line number, and
65    function name, plus a user-specific message. */
66 void
67 debug_panic (const char *file, int line, const char *function,
68              const char *message, ...)
69 {
70   va_list args;
71
72 #ifdef KERNEL
73   intr_disable ();
74 #endif
75
76   printf ("PANIC at %s:%d in %s(): ", file, line, function);
77   va_start (args, message);
78   vprintf (message, args);
79   printf ("\n");
80   va_end (args);
81
82   debug_backtrace ();
83
84 #ifdef KERNEL
85   serial_flush ();
86   for (;;);
87 #else
88   exit (1);
89 #endif
90 }
91
92 /* Prints the call stack, that is, a list of addresses, one in
93    each of the functions we are nested within.  gdb or addr2line
94    may be applied to kernel.o to translate these into file names,
95    line numbers, and function names.  */
96 void
97 debug_backtrace (void) 
98 {
99   void **frame;
100   
101   printf ("Call stack:");
102   for (frame = __builtin_frame_address (0);
103        frame != NULL && frame[0] != NULL;
104        frame = frame[0]) 
105     printf (" %p", frame[1]);
106   printf (".\n");
107 }
108 \f
109
110 /* Returns true if CLASS is enabled, false otherwise. */
111 static bool
112 class_is_enabled (const char *class) 
113 {
114   size_t i;
115   
116   if (all_enabled)
117     return true;
118
119   for (i = 0; i < enabled_cnt; i++)
120     if (!strcmp (enabled_classes[i], class))
121       return true;
122
123   return false;
124 }