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