command line option, and associated support.
Rename panic() to PANIC(). Update references.
Rename backtrace() to debug_backtrace().
case EVEN: lcr |= 0x18; break;
case MARK: lcr |= 0x28; break;
case SPACE: lcr |= 0x38; break;
- default: panic ("bad parity %d", (int) parity);
+ default: PANIC ("bad parity %d", (int) parity);
}
ASSERT (stop == 1 || stop == 2);
sema_down (&d->channel->completion_wait);
wait_while_busy (d);
if (!input_sector (d->channel, buffer))
- panic ("%s: disk read failed, sector=%"PRDSNu, d->name, sec_no);
+ PANIC ("%s: disk read failed, sector=%"PRDSNu, d->name, sec_no);
lock_release (&d->channel->lock);
}
issue_command (d, CMD_WRITE_SECTOR_RETRY);
wait_while_busy (d);
if (!output_sector (d->channel, buffer))
- panic ("%s: disk write failed, sector=%"PRDSNu, d->name, sec_no);
+ PANIC ("%s: disk write failed, sector=%"PRDSNu, d->name, sec_no);
sema_down (&d->channel->completion_wait);
lock_release (&d->channel->lock);
}
#include "interrupt.h"
#include "lib.h"
+#define MAX_CLASSES 16
+static bool all_enabled;
+static const char *enabled_classes[MAX_CLASSES];
+static size_t enabled_cnt;
+
+/* Enables the debug message classes specified in CLASSES. The
+ string CLASSES is modified by and becomes owned by this
+ function. */
+void
+debug_enable (char *classes)
+{
+ char *class, *save;
+
+ for (class = strtok_r (classes, ",", &save); class != NULL;
+ class = strtok_r (NULL, ",", &save))
+ {
+ if (strcmp (class, "all") && enabled_cnt < MAX_CLASSES)
+ enabled_classes[enabled_cnt++] = class;
+ else
+ all_enabled = true;
+ }
+}
+
+/* Checks whether CLASS is enabled. */
+static bool
+class_is_enabled (const char *class)
+{
+ size_t i;
+
+ if (all_enabled)
+ return true;
+
+ for (i = 0; i < enabled_cnt; i++)
+ if (!strcmp (enabled_classes[i], class))
+ return true;
+
+ return false;
+}
+
+/* Prints a debug message along with the source file name, line
+ number, and function name of where it was emitted. CLASS is
+ used to filter out unwanted messages. */
+void
+debug_message (const char *file, int line, const char *function,
+ const char *class, const char *message, ...)
+{
+ if (class_is_enabled (class))
+ {
+ va_list args;
+
+ enum if_level old_level = intr_disable ();
+ printk ("%s:%d: %s(): ", file, line, function);
+ va_start (args, message);
+ vprintk (message, args);
+ printk ("\n");
+ va_end (args);
+ intr_set_level (old_level);
+ }
+}
+
+/* Halts the OS, printing the source file name, line number, and
+ function name, plus a user-specific message. */
void
-panic (const char *format, ...)
+debug_panic (const char *file, int line, const char *function,
+ const char *message, ...)
{
va_list args;
intr_disable ();
- va_start (args, format);
- vprintk (format, args);
+ printk ("PANIC at %s:%d in %s(): ", file, line, function);
+ va_start (args, message);
+ vprintk (message, args);
printk ("\n");
va_end (args);
- backtrace ();
+ debug_backtrace ();
for (;;);
}
+/* Prints the call stack, that is, a list of addresses in each of
+ the functions we are nested within. gdb or addr2line may be
+ applied to kernel.o to translate these into file names, line
+ numbers, and function names. */
void
-backtrace (void)
+debug_backtrace (void)
{
void **frame;
#ifndef HEADER_DEBUG_H
#define HEADER_DEBUG_H 1
-#if __GNUC__ > 1
-#define ATTRIBUTE(X) __attribute__ (X)
-#else
-#define ATTRIBUTE(X)
-#endif
+/* GCC lets us add "attributes" to functions, function
+ parameters, etc. to indicate their properties.
+ See the GCC manual for details. */
+#define UNUSED __attribute__ ((unused))
+#define NO_RETURN __attribute__ ((noreturn))
+#define NO_INLINE __attribute__ ((noinline))
+#define PRINTF_FORMAT(FMT, FIRST) __attribute__ ((format (printf, FMT, FIRST)))
+
+/* Prints a debug message along with the source file name, line
+ number, and function name of where it was emitted. CLASS is
+ used to filter out unwanted messages. */
+#define DEBUG(CLASS, ...) \
+ debug_message (__FILE__, __LINE__, __func__, #CLASS, __VA_ARGS__)
-#define UNUSED ATTRIBUTE ((unused))
-#define NO_RETURN ATTRIBUTE ((noreturn))
-#define PRINTF_FORMAT(FMT, FIRST) ATTRIBUTE ((format (printf, FMT, FIRST)))
-#define SCANF_FORMAT(FMT, FIRST) ATTRIBUTE ((format (scanf, FMT, FIRST)))
+/* Halts the OS, printing the source file name, line number, and
+ function name, plus a user-specific message. */
+#define PANIC(...) debug_panic (__FILE__, __LINE__, __func__, __VA_ARGS__)
+
+void debug_enable (char *classes);
+void debug_message (const char *file, int line, const char *function,
+ const char *class, const char *message, ...)
+ PRINTF_FORMAT (5, 6);
+void debug_panic (const char *file, int line, const char *function,
+ const char *message, ...) PRINTF_FORMAT (4, 5) NO_RETURN;
+void debug_backtrace (void);
+
+#endif
-void panic (const char *, ...)
- __attribute__ ((format (printf, 1, 2), noreturn));
-void backtrace (void);
-#endif /* debug.h */
/* This is outside the header guard so that debug.h may be
included multiple times with different settings of NDEBUG. */
#undef NOT_REACHED
#ifndef NDEBUG
-#define ASSERT(CONDITION) \
- if (CONDITION) { \
- /* Nothing. */ \
- } else { \
- panic ("%s:%d: %s(): assertion `%s' failed.", \
- __FILE__, __LINE__, __func__, #CONDITION); \
+#define ASSERT(CONDITION) \
+ if (CONDITION) { } else { \
+ PANIC ("assertion `%s' failed.", #CONDITION); \
}
-#define NOT_REACHED() ASSERT (0)
+#define NOT_REACHED() PANIC ("executed an unreachable statement");
#else
#define ASSERT(CONDITION) ((void) 0)
#define NOT_REACHED() for (;;)
intr_panic (struct intr_frame *regs)
{
dump_intr_frame (regs);
- panic ("Panic!");
+ PANIC ("Panic!");
}
void
else
{
if (flags & PAL_ASSERT)
- panic ("palloc_get: out of pages");
+ PANIC ("palloc_get: out of pages");
}
return page;