Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge pull request #2 from gmorin/master

Debug: Backtrace and Panic functions
  • Loading branch information...
commit adc8cf56724c7a77815476d44f92929e99ec4ad5 2 parents 71ef2ec + 281c478
@ddejean ddejean authored
View
14 kernel/CUtils/assert.h
@@ -10,12 +10,14 @@
#ifndef _ASSERT_H_
#define _ASSERT_H_
-#include "stdio.h"
+#include "panic.h"
-#define assert(cond) do { \
- if (!(cond)) { \
- printf("%s (%s:%d): Assertion \"%s\" failed.", __FILE__, __func__, __LINE__, #cond); \
- } \
- } while (0)
+#define assert(cond) \
+ do { \
+ if (!(cond)) { \
+ panic("%s (%s:%d): Assertion \"%s\" failed.", \
+ __FILE__, __func__, __LINE__, #cond); \
+ } \
+ } while (0)
#endif
View
34 kernel/CUtils/backtrace.h
@@ -0,0 +1,34 @@
+/*
+ * backtrace.h
+ *
+ * Copyright (C) 2012 Simple Object Kernel project
+ * by Gaëtan Morin
+ *
+ * Backtrace Headers.
+ */
+
+#ifndef _BACKTRACE_H_
+#define _BACKTRACE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * Backtrace unwinds the stack to find the addresses of the callers of the
+ * enclosing function (the "stack trace"). Those addresses are written, in
+ * order (innermost to outermost), into the given array.
+ *
+ * @param array a pointer array capable of holding at least {@code size}
+ * elements
+ * @param size the maximum number of stack frames to unwind
+ */
+void backtrace(void **array, int size);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
View
67 kernel/CUtils/backtrace.s
@@ -0,0 +1,67 @@
+#
+# backtrace.s
+#
+# Copyright (C) 2012 Simple Object Kernel project
+# by Gaëtan Morin
+#
+# x86 (32bit) implementation of backtrace.
+#
+#
+# ---
+#
+# The idea behind this algorithm to follow the linked list formed by the base
+# pointers pushed at the beginning of each stack frame when a function is
+# entered. We assume that the word just before the base pointer in the stack
+# is indeed the return address to the caller and write that in the back trace.
+#
+# To determine when we reached the end of the stack, we assume that the linked
+# list is null-terminated. In other words, the first base pointer pushed in the
+# stack must be null. The return address pushed before that null pointer (ie.
+# first word of the stack) is not considered to be part of the back trace.
+#
+# If the first base pointer is anything other than 0, and the `size` parameter
+# is larger than the number of stack frames at the time of the call, then this
+# code WILL segfault or do somthing bad.
+#
+
+
+.globl backtrace
+
+
+backtrace: # backtrace(void **array, int size)
+ pushl %ebp
+ movl %esp, %ebp
+
+ movl 8(%ebp), %ecx # %ecx = array
+ movl 12(%ebp), %edx # %edx = size
+ leal (%ecx, %edx, 4), %edx # %edx = &array[size]
+
+backtrace.loop:
+ # Exit when:
+ # - %ecx == %edx (we wrote `size` entries into array)
+ # - %ebp is null (we reached the end of the stack)
+ #
+ cmpl %ecx, %edx
+ je backtrace.exit
+ cmpl $0, %ebp
+ je backtrace.exit
+
+ # At this point:
+ #
+ # +----------------+
+ # | RETURN ADDRESS |
+ # +----------------+
+ # EBP --> | PREVIOUS FRAME |
+ # +----------------+
+ #
+ movl 4(%ebp), %eax # %eax = return address
+ movl 0(%ebp), %ebp # %ebp = previous frame
+ movl %eax, (%ecx) # *(%ecx) = return address
+ addl $4, %ecx # %ecx++
+ jmp backtrace.loop
+
+backtrace.exit:
+ popl %ebp
+ ret
+
+
View
51 kernel/CUtils/panic.c
@@ -0,0 +1,51 @@
+#include "assert.h"
+#include "backtrace.h"
+#include "stdarg.h"
+#include "stdint.h"
+#include "stdio.h"
+#include "string.h"
+
+#ifndef MAX_STACK_TRACE_DEPTH
+#define MAX_STACK_TRACE_DEPTH 15
+#endif
+
+static void *backtrace_buffer[MAX_STACK_TRACE_DEPTH];
+
+__inline__ static void hlt(void)
+{
+ __asm__ __volatile__("hlt");
+}
+
+void panic(const char *fmt, ...)
+{
+ va_list args;
+ int i;
+ void *addr;
+
+ /* Print user message */
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+
+ /* Get the stack trace */
+ memset(backtrace_buffer, 0, MAX_STACK_TRACE_DEPTH * sizeof(void *));
+ backtrace(backtrace_buffer, MAX_STACK_TRACE_DEPTH);
+
+ /* Print the stack trace */
+ printf("\nstack trace:");
+ for (i = 0; i < MAX_STACK_TRACE_DEPTH; ++i) {
+ if (!(addr = backtrace_buffer[i])) {
+ break;
+ }
+ printf(" %3d: %08x\n", i, (uintptr_t) addr);
+ }
+
+ /* Stop here... */
+ printf("\nkernel halted!");
+ while (1) {
+ hlt();
+ }
+}
+
+
+
View
35 kernel/CUtils/panic.h
@@ -0,0 +1,35 @@
+/*
+ * panic.h
+ *
+ * Copyright (C) 2012 Simple Object Kernel project
+ * by Gaëtan Morin
+ *
+ * Kernel panic.
+ */
+
+#ifndef _PANIC_H_
+#define _PANIC_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * Panic ends the execution of the kernel with an error message and a stack
+ * trace. This function never returns to its caller (it blocks indefinitely).
+ *
+ * @param fmt a printf-like format string
+ * @param ... format string parameters
+ */
+void panic(const char *fmt, ...)
+ __attribute__((format (printf, 1, 2)));
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
View
2  kernel/Makefile
@@ -61,7 +61,7 @@ BOOT_OBJS := $(addprefix $(OUTPUT)/, $(call objetize-compilables, $(BOOT_FILES)
BOOT_DEPS := $(addprefix $(OUTPUT)/, $(call generate-dependencies, $(BOOT_FILES)))
# Library builds
-LIBRARY_NAMES := CUtils Memory
+LIBRARY_NAMES := Memory CUtils
LIBRARY_FILES := $(call dirs-to-libs, $(LIBRARY_NAMES))
LIBRARIES_OUT := $(addprefix $(OUTPUT)/, $(LIBRARY_FILES))
KERNEL_LDFLAGS += -L$(OUTPUT) $(call generate-libs-flags, $(LIBRARY_NAMES))
Please sign in to comment.
Something went wrong with that request. Please try again.