X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flib%2Fkernel%2Fdebug.c;h=22801954dd66512d489287a629371c6d88133ecf;hb=3edcfedb8e62970f3293fa676b6691f8658c3c11;hp=f6fb9dde1c4bb7090b72c051f8a4e7733f3fb08a;hpb=615bf3b3d2a8573ed6fb9ddc0055745e163ac999;p=pintos-anon diff --git a/src/lib/kernel/debug.c b/src/lib/kernel/debug.c index f6fb9dd..2280195 100644 --- a/src/lib/kernel/debug.c +++ b/src/lib/kernel/debug.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -6,6 +7,9 @@ #include #include "threads/init.h" #include "threads/interrupt.h" +#include "threads/thread.h" +#include "threads/switch.h" +#include "threads/vaddr.h" #include "devices/serial.h" /* Halts the OS, printing the source file name, line number, and @@ -18,6 +22,7 @@ debug_panic (const char *file, int line, const char *function, va_list args; intr_disable (); + console_panic (); level++; if (level == 1) @@ -44,3 +49,75 @@ debug_panic (const char *file, int line, const char *function, power_off (); 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); +}