- added thread_foreach
[pintos-anon] / src / lib / kernel / debug.c
1 #include <debug.h>
2 #include <console.h>
3 #include <stdarg.h>
4 #include <stdbool.h>
5 #include <stddef.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include "threads/init.h"
9 #include "threads/interrupt.h"
10 #include "threads/thread.h"
11 #include "threads/switch.h"
12 #include "threads/vaddr.h"
13 #include "devices/serial.h"
14
15 /* Halts the OS, printing the source file name, line number, and
16    function name, plus a user-specific message. */
17 void
18 debug_panic (const char *file, int line, const char *function,
19              const char *message, ...)
20 {
21   static int level;
22   va_list args;
23
24   intr_disable ();
25   console_panic ();
26
27   level++;
28   if (level == 1) 
29     {
30       printf ("Kernel PANIC at %s:%d in %s(): ", file, line, function);
31
32       va_start (args, message);
33       vprintf (message, args);
34       printf ("\n");
35       va_end (args);
36
37       debug_backtrace ();
38     }
39   else if (level == 2)
40     printf ("Kernel PANIC recursion at %s:%d in %s().\n",
41             file, line, function);
42   else 
43     {
44       /* Don't print anything: that's probably why we recursed. */
45     }
46
47   serial_flush ();
48   if (power_off_when_done)
49     power_off ();
50   for (;;);
51 }
52
53 /* Print call stack of a thread.
54    The thread may be running, ready, or blocked. */
55 static void
56 print_stacktrace(struct thread *t, void *aux UNUSED)
57 {
58   void *retaddr = NULL, **frame = NULL;
59   const char *status = "UNKNOWN";
60
61   switch (t->status) {
62     case THREAD_RUNNING:  
63       status = "RUNNING";
64       break;
65
66     case THREAD_READY:  
67       status = "READY";
68       break;
69
70     case THREAD_BLOCKED:  
71       status = "BLOCKED";
72       break;
73
74     default:
75       break;
76   }
77
78   printf ("Call stack of thread `%s' (status %s):", t->name, status);
79
80   if (t == thread_current()) 
81     {
82       frame = __builtin_frame_address (1);
83       retaddr = __builtin_return_address (0);
84     }
85   else
86     {
87       /* Retrieve the values of the base and instruction pointers
88          as they were saved when this thread called switch_threads. */
89       struct switch_threads_frame * saved_frame;
90
91       saved_frame = (struct switch_threads_frame *)t->stack;
92
93       /* Skip threads if they have been added to the all threads
94          list, but have never been scheduled.
95          We can identify because their `stack' member either points 
96          at the top of their kernel stack page, or the 
97          switch_threads_frame's 'eip' member points at switch_entry.
98          See also threads.c. */
99       if (t->stack == (uint8_t *)t + PGSIZE || saved_frame->eip == switch_entry)
100         {
101           printf (" thread was never scheduled.\n");
102           return;
103         }
104
105       frame = (void **) saved_frame->ebp;
106       retaddr = (void *) saved_frame->eip;
107     }
108
109   printf (" %p", retaddr);
110   for (; (uintptr_t) frame >= 0x1000 && frame[0] != NULL; frame = frame[0])
111     printf (" %p", frame[1]);
112   printf (".\n");
113 }
114
115 /* Prints call stack of all threads. */
116 void
117 debug_backtrace_all (void)
118 {
119   enum intr_level oldlevel = intr_disable ();
120
121   thread_foreach (print_stacktrace, 0);
122   intr_set_level (oldlevel);
123 }