:: commit 8460cee5ca6c5b9f0e5dfe7b8465ba2bd0b62249

mintsuki <mintsuki@protonmail.com> — 2020-11-15 16:56

parents: 36b5be1380

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
tab: 248 wrap: offon