#include <string.h>
#include "threads/init.h"
#include "threads/interrupt.h"
+#include "threads/thread.h"
+#include "threads/switch.h"
+#include "threads/vaddr.h"
#include "devices/serial.h"
+#include "devices/shutdown.h"
/* Halts the OS, printing the source file name, line number, and
function name, plus a user-specific message. */
}
serial_flush ();
- if (power_off_when_done)
- power_off ();
+ shutdown ();
for (;;);
}
+
+/* Print call stack of a thread.
+ The thread may be running, ready, or blocked. */
+static void
+print_stacktrace(struct thread *t, void *aux UNUSED)
+{
+ void *retaddr = NULL, **frame = NULL;
+ const char *status = "UNKNOWN";
+
+ switch (t->status) {
+ case THREAD_RUNNING:
+ status = "RUNNING";
+ break;
+
+ case THREAD_READY:
+ status = "READY";
+ break;
+
+ case THREAD_BLOCKED:
+ status = "BLOCKED";
+ break;
+
+ default:
+ break;
+ }
+
+ printf ("Call stack of thread `%s' (status %s):", t->name, status);
+
+ if (t == thread_current())
+ {
+ frame = __builtin_frame_address (1);
+ retaddr = __builtin_return_address (0);
+ }
+ else
+ {
+ /* Retrieve the values of the base and instruction pointers
+ as they were saved when this thread called switch_threads. */
+ struct switch_threads_frame * saved_frame;
+
+ saved_frame = (struct switch_threads_frame *)t->stack;
+
+ /* Skip threads if they have been added to the all threads
+ list, but have never been scheduled.
+ We can identify because their `stack' member either points
+ at the top of their kernel stack page, or the
+ switch_threads_frame's 'eip' member points at switch_entry.
+ See also threads.c. */
+ if (t->stack == (uint8_t *)t + PGSIZE || saved_frame->eip == switch_entry)
+ {
+ printf (" thread was never scheduled.\n");
+ return;
+ }
+
+ frame = (void **) saved_frame->ebp;
+ retaddr = (void *) saved_frame->eip;
+ }
+
+ printf (" %p", retaddr);
+ for (; (uintptr_t) frame >= 0x1000 && frame[0] != NULL; frame = frame[0])
+ printf (" %p", frame[1]);
+ printf (".\n");
+}
+
+/* Prints call stack of all threads. */
+void
+debug_backtrace_all (void)
+{
+ enum intr_level oldlevel = intr_disable ();
+
+ thread_foreach (print_stacktrace, 0);
+ intr_set_level (oldlevel);
+}