misc: Implement stacktrace
diff --git a/.gitignore b/.gitignore
index ec9d1bd5..b27effaf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
+/**/*.gen
+/**/*.map
/**/*.o
/**/*.d
/**/*.a
diff --git a/Makefile b/Makefile
index cc5beb67..5f8afdd3 100644
--- a/Makefile
+++ b/Makefile
@@ -8,6 +8,7 @@ all: stage2 decompressor
gzip -n -9 < stage2/stage2.bin > stage2/stage2.bin.gz
cd bootsect && nasm bootsect.asm -fbin -o ../limine.bin
cd pxeboot && nasm bootsect.asm -fbin -o ../limine-pxe.bin
+ cp stage2/stage2.map ./
clean: stage2-clean decompressor-clean test-clean
rm -f stage2/stage2.bin.gz
@@ -55,6 +56,7 @@ echfs-test: limine-install test.img
ext2-test: limine-install test.img
$(MAKE) -C test
+ cp stage2.map test/
rm -rf test_image/
mkdir test_image
sudo losetup -Pf --show test.img > loopback_dev
@@ -62,8 +64,7 @@ ext2-test: limine-install test.img
sudo mkfs.ext2 `cat loopback_dev`p1
sudo mount `cat loopback_dev`p1 test_image
sudo mkdir test_image/boot
- sudo cp test/test.elf test_image/boot/
- sudo cp test/limine.cfg test_image/
+ sudo cp -rv test/* test_image/boot/
sync
sudo umount test_image/
sudo losetup -d `cat loopback_dev`
@@ -80,8 +81,7 @@ fat32-test: limine-install test.img
sudo mkfs.fat -F 32 `cat loopback_dev`p1
sudo mount `cat loopback_dev`p1 test_image
sudo mkdir test_image/boot
- sudo cp test/test.elf test_image/boot/
- sudo cp test/limine.cfg test_image/
+ sudo cp -rv test/* test_image/boot/
sync
sudo umount test_image/
sudo losetup -d `cat loopback_dev`
diff --git a/decompressor/main.c b/decompressor/main.c
index 07db966f..6ef54587 100644
--- a/decompressor/main.c
+++ b/decompressor/main.c
@@ -9,8 +9,17 @@ void entry(uint8_t *compressed_stage2, size_t stage2_size, uint8_t boot_drive, i
tinf_gzip_uncompress(dest, compressed_stage2, stage2_size);
- __attribute__((noreturn))
- void (*stage2)(uint8_t boot_drive, int pxe) = (void *)dest;
+ asm volatile (
+ "mov esp, 0x7c00\n\t"
+ "xor ebp, ebp\n\t"
+ "push %1\n\t"
+ "push %0\n\t"
+ "push 0\n\t"
+ "jmp 0x8000\n\t"
+ :
+ : "r" ((uint32_t)boot_drive), "r" (pxe)
+ : "memory"
+ );
- stage2(boot_drive, pxe);
+ for (;;);
}
diff --git a/limine-pxe.bin b/limine-pxe.bin
index 0e50a21f..b7522ef6 100644
Binary files a/limine-pxe.bin and b/limine-pxe.bin differ
diff --git a/limine.bin b/limine.bin
index 82ca5687..0d10becd 100644
Binary files a/limine.bin and b/limine.bin differ
diff --git a/stage2/Makefile b/stage2/Makefile
index 8ac4c472..9e4ccdcf 100644
--- a/stage2/Makefile
+++ b/stage2/Makefile
@@ -1,9 +1,10 @@
CC = i386-elf-gcc
LD = i386-elf-gcc
OBJCOPY = i386-elf-objcopy
+OBJDUMP = i386-elf-objdump
WERROR = -Werror
-CFLAGS = -flto -Os -pipe -Wall -Wextra $(WERROR)
+CFLAGS = -Os -pipe -Wall -Wextra $(WERROR)
INTERNAL_CFLAGS = \
-std=gnu11 \
@@ -11,7 +12,7 @@ INTERNAL_CFLAGS = \
-ffreestanding \
-fno-stack-protector \
-fno-pic \
- -fomit-frame-pointer \
+ -fno-omit-frame-pointer \
-Wno-address-of-packed-member \
-masm=intel \
-mno-80387 \
@@ -23,7 +24,7 @@ INTERNAL_CFLAGS = \
-I. \
-I..
-LDFLAGS = -flto -Os
+LDFLAGS = -Os
INTERNAL_LDFLAGS = \
-lgcc \
@@ -41,11 +42,17 @@ ASM_FILES := $(shell find ./ -type f -name '*.asm' | sort)
OBJ := $(ASM_FILES:.asm=.o) $(C_FILES:.c=.o)
HEADER_DEPS := $(C_FILES:.c=.d)
-all: stage2.bin
+all: stage2.map stage2.bin
-stage2.bin: $(OBJ)
- $(LD) $(OBJ) $(LDFLAGS) $(INTERNAL_LDFLAGS) -o stage2.elf
- $(OBJCOPY) -O binary stage2.elf stage2.bin
+stage2.map: stage2.elf
+ ./gensyms.sh $(OBJDUMP)
+ nasm symlist.gen -f bin -o $@
+
+stage2.bin: stage2.elf
+ $(OBJCOPY) -O binary $< $@
+
+stage2.elf: $(OBJ)
+ $(LD) $(OBJ) $(LDFLAGS) $(INTERNAL_LDFLAGS) -o $@
-include $(HEADER_DEPS)
@@ -56,4 +63,4 @@ stage2.bin: $(OBJ)
nasm $< -f elf32 -o $@
clean:
- rm -f stage2.bin stage2.elf $(OBJ) $(HEADER_DEPS)
+ rm -f symlist.gen stage2.map stage2.bin stage2.elf $(OBJ) $(HEADER_DEPS)
diff --git a/stage2/gensyms.sh b/stage2/gensyms.sh
new file mode 100755
index 00000000..16145d55
--- /dev/null
+++ b/stage2/gensyms.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+set -e
+
+TMP1=$(mktemp)
+TMP2=$(mktemp)
+TMP3=$(mktemp)
+
+$1 -t stage2.elf | sed '/\bd\b/d' | sort > "$TMP1"
+grep "\.text" < "$TMP1" | cut -d' ' -f1 > "$TMP2"
+grep "\.text" < "$TMP1" | awk 'NF{ print $NF }' > "$TMP3"
+
+paste -d'$' "$TMP2" "$TMP3" | sed 's/^/dd 0x/g' | sed 's/$/", 0/g' | sed 's/\$/\ndb "/g' > symlist.gen
+
+echo "dd 0xffffffff" >> symlist.gen
+
+rm "$TMP1" "$TMP2" "$TMP3"
diff --git a/stage2/lib/blib.c b/stage2/lib/blib.c
index 3112bf4f..ce4596e2 100644
--- a/stage2/lib/blib.c
+++ b/stage2/lib/blib.c
@@ -4,6 +4,7 @@
#include <lib/libc.h>
#include <lib/blib.h>
#include <lib/print.h>
+#include <lib/trace.h>
uint8_t boot_drive;
@@ -73,6 +74,9 @@ __attribute__((noreturn)) void panic(const char *fmt, ...) {
va_end(args);
+ print("\n");
+ print_stacktrace(NULL);
+
for (;;) {
asm volatile ("hlt" ::: "memory");
}
diff --git a/stage2/lib/trace.c b/stage2/lib/trace.c
new file mode 100644
index 00000000..1e392678
--- /dev/null
+++ b/stage2/lib/trace.c
@@ -0,0 +1,75 @@
+#include <stddef.h>
+#include <stdint.h>
+#include <lib/trace.h>
+#include <lib/blib.h>
+#include <lib/config.h>
+#include <lib/print.h>
+#include <lib/uri.h>
+#include <fs/file.h>
+#include <mm/pmm.h>
+
+static char *stage2_map = NULL;
+
+void trace_init(void) {
+ char map_filename[80];
+ if (!config_get_value(map_filename, 0, 80, "STAGE2_MAP"))
+ return;
+
+ struct file_handle stage2_map_file;
+ if (!uri_open(&stage2_map_file, map_filename))
+ panic("Could not open stage2 map file `%s`", map_filename);
+
+ stage2_map = ext_mem_alloc(stage2_map_file.size);
+ fread(&stage2_map_file, stage2_map, 0, stage2_map_file.size);
+
+ print("trace: Stage 2 map file `%s` loaded.\n", map_filename);
+}
+
+char *trace_address(size_t *off, size_t addr) {
+ if (!stage2_map)
+ return NULL;
+
+ uint32_t prev_addr = 0;
+ char *prev_sym = NULL;
+
+ for (size_t i = 0;;) {
+ if (*((uint32_t *)&stage2_map[i]) >= addr) {
+ *off = addr - prev_addr;
+ return prev_sym;
+ }
+ prev_addr = *((uint32_t *)&stage2_map[i]);
+ i += sizeof(uint32_t);
+ prev_sym = &stage2_map[i];
+ while (stage2_map[i++] != 0);
+ }
+}
+
+void print_stacktrace(size_t *base_ptr) {
+ if (!stage2_map)
+ print("trace: Symbol names won't be resolved due to missing map file.\n");
+
+ if (base_ptr == NULL) {
+ asm volatile (
+ "mov %0, ebp"
+ : "=g"(base_ptr)
+ :: "memory"
+ );
+ }
+ print("Stacktrace:\n");
+ for (;;) {
+ size_t old_bp = base_ptr[0];
+ size_t ret_addr = base_ptr[1];
+ if (!ret_addr)
+ break;
+ size_t off;
+ char *name = trace_address(&off, ret_addr);
+ if (name)
+ print(" [%x] <%s+%x>\n", ret_addr, name, off);
+ else
+ print(" [%x]\n", ret_addr);
+ if (!old_bp)
+ break;
+ base_ptr = (void*)old_bp;
+ }
+ print("End of trace.\n");
+}
diff --git a/stage2/lib/trace.h b/stage2/lib/trace.h
new file mode 100644
index 00000000..30c3cf47
--- /dev/null
+++ b/stage2/lib/trace.h
@@ -0,0 +1,10 @@
+#ifndef __LIB__TRACE_H__
+#define __LIB__TRACE_H__
+
+#include <stdint.h>
+
+void trace_init(void);
+char *trace_address(size_t *off, size_t addr);
+void print_stacktrace(size_t *base_ptr);
+
+#endif
diff --git a/stage2/main.c b/stage2/main.c
index dfdd9d4e..a2f2bb1f 100644
--- a/stage2/main.c
+++ b/stage2/main.c
@@ -5,6 +5,7 @@
#include <lib/libc.h>
#include <lib/part.h>
#include <lib/config.h>
+#include <lib/trace.h>
#include <sys/e820.h>
#include <sys/a20.h>
#include <lib/print.h>
@@ -67,6 +68,8 @@ void entry(uint8_t _boot_drive, int pxe_boot) {
}
}
+ trace_init();
+
char *cmdline = menu();
char proto[32];
diff --git a/test/limine.cfg b/test/limine.cfg
index 3d38a940..da6cfcd1 100644
--- a/test/limine.cfg
+++ b/test/limine.cfg
@@ -3,21 +3,25 @@ TIMEOUT=3
GRAPHICS=yes
MENU_RESOLUTION=1024x768
E9_OUTPUT=yes
+STAGE2_MAP=bios://:1/boot/stage2.map
THEME_COLOURS=60000000;aa0000;00aaff;aa5500;0000aa;aa00aa;9076de;aaaaaa
THEME_MARGIN=64
-BACKGROUND_PATH=guid://@GUID@/bg.bmp
+BACKGROUND_PATH=bios://:1/boot/bg.bmp
:Stivale Test
PROTOCOL=stivale
-KERNEL_PATH=guid://@GUID@/boot/test.elf
+KERNEL_PATH=bios://:1/boot/test.elf
KERNEL_CMDLINE=Hi! This is an example!
MODULE_PATH=bios://:1/boot/test.elf
MODULE_STRING=yooooo
+MODULE_PATH=bios://:1/boot/bg.bmp
+MODULE_STRING=yooooo
+
:Stivale2 Test
PROTOCOL=stivale2
@@ -25,5 +29,5 @@ RESOLUTION=640x480x16
KERNEL_PATH=bios://:1/boot/test.elf
KERNEL_CMDLINE=Woah! Another example!
-MODULE_PATH=guid://@GUID@/boot/test.elf
+MODULE_PATH=bios://:1/boot/bg.bmp
MODULE_STRING=yooooo
