This repository has been archived on 2021-05-26. You can view files and clone it, but cannot push or open issues or pull requests.
OS/pintos-env/pintos/lib/kernel/debug.c

124 lines
3 KiB
C
Raw Permalink Normal View History

#include <debug.h>
#include <console.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#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. */
void
debug_panic (const char *file, int line, const char *function,
const char *message, ...)
{
static int level;
va_list args;
intr_disable ();
console_panic ();
level++;
if (level == 1)
{
printf ("Kernel PANIC at %s:%d in %s(): ", file, line, function);
va_start (args, message);
vprintf (message, args);
printf ("\n");
va_end (args);
debug_backtrace ();
}
else if (level == 2)
printf ("Kernel PANIC recursion at %s:%d in %s().\n",
file, line, function);
else
{
/* Don't print anything: that's probably why we recursed. */
}
serial_flush ();
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);
}