Add a suggestion to use `backtrace' and a reference to the manual to
[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   printf ("The `backtrace' program can make call stacks useful.\n"
92           "Read \"Backtraces\" in the \"Debugging Tools\" chapter\n"
93           "of the Pintos documentation for more information.\n");
94   
95 #ifdef KERNEL
96   serial_flush ();
97   if (power_off_when_done)
98     power_off ();
99   for (;;);
100 #else
101   exit (1);
102 #endif
103 }
104
105 /* Prints the call stack, that is, a list of addresses, one in
106    each of the functions we are nested within.  gdb or addr2line
107    may be applied to kernel.o to translate these into file names,
108    line numbers, and function names.  */
109 void
110 debug_backtrace (void) 
111 {
112   void **frame;
113   
114   printf ("Call stack:");
115   for (frame = __builtin_frame_address (0);
116        frame != NULL && frame[0] != NULL;
117        frame = frame[0]) 
118     printf (" %p", frame[1]);
119   printf (".\n");
120 }
121 \f
122
123 /* Returns true if CLASS is enabled, false otherwise. */
124 static bool
125 class_is_enabled (const char *class) 
126 {
127   size_t i;
128   
129   if (all_enabled)
130     return true;
131
132   for (i = 0; i < enabled_cnt; i++)
133     if (!strcmp (enabled_classes[i], class))
134       return true;
135
136   return false;
137 }