summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/backtrace.h20
-rw-r--r--include/panic.h2
-rw-r--r--src/arch/amd64/backtrace.c53
-rw-r--r--src/arch/amd64/boot.S7
-rw-r--r--src/arch/amd64/idt.S13
-rw-r--r--src/arch/amd64/idt.c5
-rw-r--r--src/arch/amd64/panic.c15
-rw-r--r--src/kmain.c24
8 files changed, 130 insertions, 9 deletions
diff --git a/include/backtrace.h b/include/backtrace.h
new file mode 100644
index 0000000..2abece7
--- /dev/null
+++ b/include/backtrace.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <stddef.h>
+
+// Fill dst with a stack trace consisting of return addresses
+// in order from top to bottom. returns the number filled (at most len)
+size_t backtrace(void **dst, size_t len);
+
+
+// same as backtrace but with specified instruction and base pointer
+size_t backtrace_ex(void **dst, size_t len, void* ip, void *bp);
+
+// TODO symbols
+//size_t backtrace_symbols(char *const *dst, size_t len);
+
+// Log a backtrace
+void log_backtrace();
+
+// same as log_backtrace with specified insruction and base pointer
+void log_backtrace_ex(void *ip, void *bp);
diff --git a/include/panic.h b/include/panic.h
index 21715fd..4f8592e 100644
--- a/include/panic.h
+++ b/include/panic.h
@@ -6,3 +6,5 @@
#define panic(msg) _panic_impl(_PANIC_STR(__LINE__), __FILE__, msg)
_Noreturn void _panic_impl(char *line, char *file, char *msg);
+
+_Noreturn void panic_interrupt(void *ip, void *bp, char *msg);
diff --git a/src/arch/amd64/backtrace.c b/src/arch/amd64/backtrace.c
new file mode 100644
index 0000000..c882fa0
--- /dev/null
+++ b/src/arch/amd64/backtrace.c
@@ -0,0 +1,53 @@
+#include <backtrace.h>
+#include <lib.h>
+#include "serial.h"
+
+struct stackframe {
+ struct stackframe *rbp;
+ void *rip;
+};
+
+size_t backtrace(void **dst, size_t len) {
+ struct stackframe *rbp;
+ __asm__ volatile ("mov %%rbp, %0" : "=r"(rbp));
+ return backtrace_ex(dst, len, rbp->rip, rbp->rbp);
+}
+
+size_t backtrace_ex(void **dst, size_t len, void *ip, void *bp) {
+ struct stackframe *frame = bp;
+ __asm__ volatile ("mov %%rbp, %0" : "=r"(frame));
+ if(len > 0) {
+ dst[0] = ip;
+ }
+ size_t i;
+ for(i = 1; frame && i < len; i++) {
+ dst[i] = frame->rip;
+ frame = frame->rbp;
+ }
+ return i;
+}
+
+void log_backtrace() {
+ struct stackframe *rbp;
+ __asm__ volatile ("mov %%rbp, %0" : "=r"(rbp));
+ log_backtrace_ex(rbp->rip, rbp->rbp);
+}
+
+
+void log_backtrace_ex(void *ip, void *bp) {
+ struct stackframe *frame = bp;
+ char buf[20];
+ serial_out_str("Stack trace:\n");
+ ultoa((size_t)ip, buf, 16);
+ serial_out_str(" 0x");
+ serial_out_str(buf);
+ serial_out_str("\n");
+ while(frame) {
+ ultoa((size_t)frame->rip, buf, 16);
+ serial_out_str(" 0x");
+ serial_out_str(buf);
+ serial_out_str("\n");
+ frame = frame->rbp;
+ }
+
+}
diff --git a/src/arch/amd64/boot.S b/src/arch/amd64/boot.S
index c6145d5..6768beb 100644
--- a/src/arch/amd64/boot.S
+++ b/src/arch/amd64/boot.S
@@ -136,13 +136,16 @@ start:
bits 64
code64:
- mov dx, 16
- mov ds, dx
+ mov dx, 16 ; set segment registers
+ mov ds, dx ; so that interrupts work
mov ss, dx
+ xor rbp, rbp ; set ebp to 0 so we know where to end stack traces
+
pop rdi
call amd64_shim
mov rdi, rax
+
sti
call kmain
cli
diff --git a/src/arch/amd64/idt.S b/src/arch/amd64/idt.S
index 32670c8..8cb537e 100644
--- a/src/arch/amd64/idt.S
+++ b/src/arch/amd64/idt.S
@@ -49,8 +49,10 @@ align 8
isr_stub_%+%1:
PUSHALL
cld
- mov rdi, %1
- mov rsi, 0
+ mov rdi, %1 ; exception number
+ mov rsi, 0 ; placeholder error code
+ mov rdx, [rsp + 15 * 8] ; instruction pointer
+ mov rcx, rbp ; base pointer for stack trace
call idt_exception_handler
POPALL
iretq
@@ -64,10 +66,13 @@ align 8
isr_stub_%+%1:
PUSHALL
cld
- mov rdi, %1
- pop rsi
+ mov rdi, %1 ; exception number
+ mov rsi, [rsp + 15 * 8] ; error code
+ mov rdx, [rsp + 16 * 8] ; instruction pointer
+ mov rcx, rbp ; base pointer for stack trace
call idt_exception_handler
POPALL
+ sub rsp, 8 ; discard error code
iretq
%endmacro
diff --git a/src/arch/amd64/idt.c b/src/arch/amd64/idt.c
index 83b792c..b4a11bb 100644
--- a/src/arch/amd64/idt.c
+++ b/src/arch/amd64/idt.c
@@ -4,6 +4,7 @@
#include <lib.h>
#include <serial.h>
+#include "backtrace.h"
#include "idt.h"
#include "pic.h"
@@ -107,7 +108,7 @@ char *EXCEPTIONS[] = {
"0x1F Reserved",
};
-void idt_exception_handler(uint64_t exception, uint64_t code) {
+void idt_exception_handler(uint64_t exception, uint64_t code, void *rip, void *rbp) {
// TODO don't just panic
char buf[24];
char msg[256] = "Exception ";
@@ -127,7 +128,7 @@ void idt_exception_handler(uint64_t exception, uint64_t code) {
strcat(msg, buf);
}
- panic(msg);
+ panic_interrupt(rip, rbp, msg);
}
void idt_pic_eoi(uint8_t exception) {
diff --git a/src/arch/amd64/panic.c b/src/arch/amd64/panic.c
index c034b90..7f54f98 100644
--- a/src/arch/amd64/panic.c
+++ b/src/arch/amd64/panic.c
@@ -1,4 +1,5 @@
#include <panic.h>
+#include <backtrace.h>
#include "serial.h"
#include "bindings.h"
@@ -12,7 +13,19 @@ _Noreturn void _panic_impl(char *line, char *file, char *msg) {
serial_out_str(line);
serial_out_str(":\n");
serial_out_str(msg);
- serial_out('\n');
+ serial_out_str("\n\n");
+ log_backtrace();
+ while (1) {
+ halt();
+ }
+}
+
+_Noreturn void panic_interrupt(void *ip, void *bp, char *msg) {
+ cli();
+ serial_out_str("\n\n!!! PANIC !!!\n");
+ serial_out_str(msg);
+ serial_out_str("\n\n");
+ log_backtrace_ex(ip, bp);
while (1) {
halt();
}
diff --git a/src/kmain.c b/src/kmain.c
index d5bee56..b55b6a5 100644
--- a/src/kmain.c
+++ b/src/kmain.c
@@ -4,6 +4,30 @@
#include <fb.h>
#include <shim.h>
+void print_memory() {
+ size_t WIDTH = 64;
+
+ for(size_t i = 0;; i += WIDTH) {
+ char buf[20];
+ ultoa(i, buf, 16);
+ serial_out_str("0x");
+ for(size_t k = 0; k < 6 - strlen(buf); k++) {
+ serial_out('0');
+ }
+ serial_out_str(buf);
+ serial_out_str(": ");
+ for(size_t j = 0; j < WIDTH; j++) {
+ char x = *(char *)(i + j);
+ if(x < 0x20 || x >= 0x7f) {
+ serial_out('.');
+ } else {
+ serial_out(x);
+ }
+ }
+ serial_out('\n');
+ }
+}
+
void kmain(struct boot_info *info) {
memory_init(info->map);
serial_out_str("entered kmain\n");