summaryrefslogtreecommitdiffstats
path: root/lib/kernel/debug.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel/debug.c')
-rw-r--r--lib/kernel/debug.c123
1 files changed, 123 insertions, 0 deletions
diff --git a/lib/kernel/debug.c b/lib/kernel/debug.c
new file mode 100644
index 0000000..b12f4f9
--- /dev/null
+++ b/lib/kernel/debug.c
@@ -0,0 +1,123 @@
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#include "devices/shutdown.h"
15
16/* Halts the OS, printing the source file name, line number, and
17 function name, plus a user-specific message. */
18void
19debug_panic (const char *file, int line, const char *function,
20 const char *message, ...)
21{
22 static int level;
23 va_list args;
24
25 intr_disable ();
26 console_panic ();
27
28 level++;
29 if (level == 1)
30 {
31 printf ("Kernel PANIC at %s:%d in %s(): ", file, line, function);
32
33 va_start (args, message);
34 vprintf (message, args);
35 printf ("\n");
36 va_end (args);
37
38 debug_backtrace ();
39 }
40 else if (level == 2)
41 printf ("Kernel PANIC recursion at %s:%d in %s().\n",
42 file, line, function);
43 else
44 {
45 /* Don't print anything: that's probably why we recursed. */
46 }
47
48 serial_flush ();
49 shutdown ();
50 for (;;);
51}
52
53/* Print call stack of a thread.
54 The thread may be running, ready, or blocked. */
55static void
56print_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. */
116void
117debug_backtrace_all (void)
118{
119 enum intr_level oldlevel = intr_disable ();
120
121 thread_foreach (print_stacktrace, 0);
122 intr_set_level (oldlevel);
123}