From 6c70040f57cc5c3fd83bc37845f3bab91bf4044f Mon Sep 17 00:00:00 2001 From: Nexoniarz Date: Sun, 13 Sep 2026 15:05:46 +0200 Subject: [PATCH] build: a gdb target, because the tree had no source-level debugger QEMU carries a gdb stub and exposing it costs two flags. `make qemu-gdb` holds the machine before its first instruction and waits on port 26000; 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. .gdbinit does the connecting, and documents the one confusing part rather than leaving it to be rediscovered: at the reset vector a breakpoint on a kernel symbol fails with "Cannot access memory at 0xffff8000...", because the kernel links into the high half and nothing is mapped there until it enables paging. Symbols resolve fine -- gdb knows kmain is main.c:32 -- the address just is not addressable yet. Continue, let it boot, interrupt, and everything works. This is for QEMU. On hardware with no serial port the tools are the on-screen kernel log and PSOGM's QR code, which is what that QR code has always been for. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01VQ7Qx8E1q1M1bbCq8QLHS2 --- .gdbinit | 39 +++++++++++++++++++++++++++++++++++++++ Makefile | 24 ++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 .gdbinit 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