diff --git a/.gdbinit b/.gdbinit new file mode 100644 index 0000000..589d968 --- /dev/null +++ b/.gdbinit @@ -0,0 +1,39 @@ +# SchOS kernel debugging. +# +# gdb refuses to auto-load this unless the directory is trusted. Once, in +# ~/.gdbinit: +# +# add-auto-load-safe-path /home/nexoniarz/Dokumenty/Projects/SchOS +# +# Then: make qemu-gdb (one terminal) +# gdb build/kernel/kernel (another) + +set confirm off +set architecture i386:x86-64 +target remote 127.0.0.1:26000 + +# You are stopped at the reset vector, 0xfff0, with the firmware not yet run. +# +# A breakpoint on a kernel symbol will NOT take here, and the error is +# confusing rather than wrong: +# +# Cannot insert breakpoint 1. Cannot access memory at 0xffff800000104fc2 +# +# The kernel links at 0xffff8000_00000000 and nothing is mapped there until it +# turns paging on. Symbols resolve -- gdb knows kmain is main.c:32 -- but the +# address is not addressable yet. +# +# So: `continue`, let the firmware and the loader run, and interrupt with ^C +# once SchOS is up. Every kernel symbol works from then on, because the high +# half is mapped and stays mapped. +# +# (gdb) continue +# ... SchOS boots ... +# ^C +# (gdb) break vt_switch +# (gdb) continue +# +# For the early boot itself -- entry.S, the long-mode switch, the handoff from +# the loader -- break on the *physical* address instead: the kernel is loaded +# at 1 MB, so `break *0x100000` catches the entry point before paging. +echo \n=== SchOS: stopped at reset. `continue`, then ^C once it boots. ===\n\n diff --git a/Makefile b/Makefile index 2920007..35ba8ef 100644 --- a/Makefile +++ b/Makefile @@ -1052,6 +1052,30 @@ OVMF_DRIVES = -drive if=pflash,format=raw,unit=0,readonly=on,file=$(OVMF_CODE) \ # whenever /dev/kvm exists -- see QEMU_ACCEL. This target differs only in # insisting on it, which is what you want when the point is to find out why the # host has no /dev/kvm rather than to quietly get a slow machine. +# Source-level debugging, which the tree had no way to do. +# +# QEMU carries a gdb stub and it costs nothing to expose: -S holds the machine +# before its first instruction, -gdb waits for a connection. Attach and you get +# breakpoints, single-stepping and symbols in kernel code -- including the +# early boot the crash screen cannot reach and the serial console has not +# started for. +# +# terminal 1: make qemu-gdb +# terminal 2: gdb build/kernel/kernel +# (gdb) target remote :26000 +# (gdb) break kmain +# (gdb) continue +# +# .gdbinit in the repo root does the connecting, so `gdb` alone is enough if +# gdb is allowed to load it -- see the file for the one line that needs. +GDBPORT ?= 26000 + +qemu-gdb: esp $(BUILD)/schfs.img $(OVMF_CODE) $(OVMF_VARS) + @echo "waiting for gdb on port $(GDBPORT) -- attach, then 'continue'" + $(QEMU) -serial mon:stdio $(QEMU_DISPLAY) $(QEMU_INPUT) $(QEMU_ACCEL) $(QEMU_NET) \ + $(OVMF_DRIVES) -m 1G -smp 1 -machine pc-i440fx-9.2 \ + -S -gdb tcp::$(GDBPORT) + qemu-kvm: esp $(BUILD)/schfs.img $(OVMF_CODE) $(OVMF_VARS) $(QEMU) -enable-kvm -serial mon:stdio $(QEMU_DISPLAY) $(QEMU_INPUT) $(QEMU_NET) -cpu host \ $(OVMF_DRIVES) -m 1G -smp $(SMP) -machine pc-i440fx-9.2