Power off on kernel 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 or user program, printing the source file name,
65    line number, and function name, plus a user-specific
66    message. */
67 void
68 debug_panic (const char *file, int line, const char *function,
69              const char *message, ...)
70 {
71   va_list args;
72
73 #ifdef KERNEL
74   intr_disable ();
75 #endif
76
77 #ifdef KERNEL
78   printf ("Kernel PANIC at %s:%d in %s(): ", file, line, function);
79 #else
80   printf ("User process panic at %s:%d in %s(): ", file, line, function);
81 #endif
82
83   va_start (args, message);
84   vprintf (message, args);
85   printf ("\n");
86   va_end (args);
87
88   debug_backtrace ();
89
90 #ifdef KERNEL
91   serial_flush ();
92   power_off ();
93 #else
94   exit (1);
95 #endif
96 }
97
98 /* Prints the call stack, that is, a list of addresses, one in
99    each of the functions we are nested within.  gdb or addr2line
100    may be applied to kernel.o to translate these into file names,
101    line numbers, and function names.  */
102 void
103 debug_backtrace (void) 
104 {
105   void **frame;
106   
107   printf ("Call stack:");
108   for (frame = __builtin_frame_address (0);
109        frame != NULL && frame[0] != NULL;
110        frame = frame[0]) 
111     printf (" %p", frame[1]);
112   printf (".\n");
113 }
114 \f
115
116 /* Returns true if CLASS is enabled, false otherwise. */
117 static bool
118 class_is_enabled (const char *class) 
119 {
120   size_t i;
121   
122   if (all_enabled)
123     return true;
124
125   for (i = 0; i < enabled_cnt; i++)
126     if (!strcmp (enabled_classes[i], class))
127       return true;
128
129   return false;
130 }