From 06835ecbd4acaa37597988f52f881daea59d7716 Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Tue, 30 Jul 2024 16:10:58 +0200 Subject: [PATCH] dbgutil: automatically switch to the kernel if booting from preboot --- dbgutil/oro_debug_suite/cmd/boot.py | 31 ++++++++++++++++++++-- dbgutil/oro_debug_suite/service/autosym.py | 26 +++++++++++++++++- oro-arch-aarch64/src/dbgutil.rs | 11 ++++++++ oro-arch-aarch64/src/lib.rs | 2 +- oro-arch-aarch64/src/xfer.rs | 4 +++ oro-arch-x86_64/src/dbgutil.rs | 18 +++++++++++++ oro-arch-x86_64/src/lib.rs | 3 +++ oro-arch-x86_64/src/xfer.rs | 4 +++ 8 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 oro-arch-x86_64/src/dbgutil.rs diff --git a/dbgutil/oro_debug_suite/cmd/boot.py b/dbgutil/oro_debug_suite/cmd/boot.py index c57db090..18984727 100644 --- a/dbgutil/oro_debug_suite/cmd/boot.py +++ b/dbgutil/oro_debug_suite/cmd/boot.py @@ -1,10 +1,10 @@ import gdb # type: ignore import os from os import path -from ..log import log, error +from ..log import log, error, warn, debug from .. import gdb_util import subprocess -from ..service import QEMU +from ..service import QEMU, SYMBOLS class BootCmd(gdb.Command): @@ -283,6 +283,16 @@ def copyfile(src, dst): with gdb_util.parameter("confirm", False): gdb.execute(f"file {limine_path}", to_string=False, from_tty=True) + # Set an auto-switch breakpoint if we found one + kernel_will_switch_sym = SYMBOLS.get_kernel_will_transfer() + if kernel_will_switch_sym: + log("setting kernel switch breakpoint") + SwitchKernelBreakpoint(kernel_will_switch_sym, kernel_path) + else: + warn( + "no kernel switch symbol found; will not automatically switch to kernel image" + ) + if auto_continue: log("setting _start breakpoint") gdb.Breakpoint("_start", internal=True, temporary=True, qualified=True) @@ -294,5 +304,22 @@ def copyfile(src, dst): log("(note: _start breakpoint was NOT set)") +class SwitchKernelBreakpoint(gdb.Breakpoint): + def __init__(self, at, switch_to_file): + super(SwitchKernelBreakpoint, self).__init__( + at, internal=True, temporary=True, qualified=True + ) + self.silent = True + self._switch_to_file = switch_to_file + + def stop(self): + debug( + "preboot environment is about to jump to kernel; switching to kernel image file" + ) + with gdb_util.parameter("confirm", False): + gdb.execute(f"file {self._switch_to_file}", to_string=False, from_tty=True) + return False # don't stop + + BootCmd() BootCmdLimine() diff --git a/dbgutil/oro_debug_suite/service/autosym.py b/dbgutil/oro_debug_suite/service/autosym.py index d02b6cde..fd4215fb 100644 --- a/dbgutil/oro_debug_suite/service/autosym.py +++ b/dbgutil/oro_debug_suite/service/autosym.py @@ -3,8 +3,24 @@ ## AArch64: AT S1E1R instruction stub SYM_AARCH64_ATS1E1R = "oro_arch_aarch64::dbgutil::__oro_dbgutil_ATS1E1R" +## AArch64: Transfer to kernel function hook +SYM_AARCH64_KERNEL_TRANSFER = ( + "oro_arch_aarch64::dbgutil::__oro_dbgutil_kernel_will_transfer" +) +## x86_64: Transfer to kernel function hook +SYM_X86_64_KERNEL_TRANSFER = ( + "oro_arch_x86_64::dbgutil::__oro_dbgutil_kernel_will_transfer" +) -TRACKED_SYMBOLS = frozenset(set([("f", SYM_AARCH64_ATS1E1R)])) +TRACKED_SYMBOLS = frozenset( + set( + [ + ("f", SYM_AARCH64_ATS1E1R), + ("f", SYM_AARCH64_KERNEL_TRANSFER), + ("f", SYM_X86_64_KERNEL_TRANSFER), + ] + ) +) SYMBOL_FUNCTION_DOMAIN = ( gdb.SYMBOL_FUNCTION_DOMAIN @@ -23,6 +39,14 @@ def __init__(self): def get(self, sym): return self.__symbols.get(sym) + def get_kernel_will_transfer(self): + if self.get(SYM_AARCH64_KERNEL_TRANSFER): + return SYM_AARCH64_KERNEL_TRANSFER + elif self.get(SYM_X86_64_KERNEL_TRANSFER): + return SYM_X86_64_KERNEL_TRANSFER + else: + return None + def _on_objfile_freed(self, objfile): for _, sym in TRACKED_SYMBOLS: if sym in self.__symbols and self.__symbols[sym][1] == objfile: diff --git a/oro-arch-aarch64/src/dbgutil.rs b/oro-arch-aarch64/src/dbgutil.rs index 883ee8e7..8d784698 100644 --- a/oro-arch-aarch64/src/dbgutil.rs +++ b/oro-arch-aarch64/src/dbgutil.rs @@ -20,3 +20,14 @@ pub extern "C" fn __oro_dbgutil_ATS1E1R() -> ! { asm!("AT S1E1R, x0", "nop", options(noreturn)); } } + +/// Transfer marker stub for `gdbutil` that allows the debugger to switch +/// to the kernel image at an opportune time. +#[no_mangle] +#[link_section = ".text.force_keep"] +pub extern "C" fn __oro_dbgutil_kernel_will_transfer() { + // SAFETY(qix-): This is a marker function for GDB to switch to the kernel image. + unsafe { + asm!("nop", options(nostack, nomem, preserves_flags)); + } +} diff --git a/oro-arch-aarch64/src/lib.rs b/oro-arch-aarch64/src/lib.rs index 1410d7b9..71ca80e1 100644 --- a/oro-arch-aarch64/src/lib.rs +++ b/oro-arch-aarch64/src/lib.rs @@ -27,7 +27,7 @@ #![cfg(not(all(doc, not(target_arch = "aarch64"))))] #[cfg(debug_assertions)] -mod dbgutil; +pub(crate) mod dbgutil; pub(crate) mod arch; pub(crate) mod asm; diff --git a/oro-arch-aarch64/src/xfer.rs b/oro-arch-aarch64/src/xfer.rs index 4ce42dd3..b4250676 100644 --- a/oro-arch-aarch64/src/xfer.rs +++ b/oro-arch-aarch64/src/xfer.rs @@ -164,6 +164,10 @@ pub unsafe fn transfer( in("x0") stubs_page_table_phys, ); + // Tell dbgutil we're about to switch + #[cfg(debug_assertions)] + crate::dbgutil::__oro_dbgutil_kernel_will_transfer(); + // Populate registers and jump to stubs asm!( "isb", diff --git a/oro-arch-x86_64/src/dbgutil.rs b/oro-arch-x86_64/src/dbgutil.rs new file mode 100644 index 00000000..bceea85f --- /dev/null +++ b/oro-arch-x86_64/src/dbgutil.rs @@ -0,0 +1,18 @@ +//! Stubs and other internal functionality for the `dbgutil` suite +//! of Oro-specific GDB debugging utilities. + +#[cfg(not(debug_assertions))] +compile_error!("The `dbgutil` module should only be used in debug builds."); + +use core::arch::asm; + +/// Transfer marker stub for `gdbutil` that allows the debugger to switch +/// to the kernel image at an opportune time. +#[no_mangle] +#[link_section = ".text.force_keep"] +pub extern "C" fn __oro_dbgutil_kernel_will_transfer() { + // SAFETY(qix-): This is a marker function for GDB to switch to the kernel image. + unsafe { + asm!("nop", options(nostack, nomem, preserves_flags)); + } +} diff --git a/oro-arch-x86_64/src/lib.rs b/oro-arch-x86_64/src/lib.rs index 2779e67b..1b26e628 100644 --- a/oro-arch-x86_64/src/lib.rs +++ b/oro-arch-x86_64/src/lib.rs @@ -59,6 +59,9 @@ )] #![cfg(not(all(doc, not(target_arch = "x86_64"))))] +#[cfg(debug_assertions)] +pub(crate) mod dbgutil; + pub(crate) mod arch; pub(crate) mod asm; pub(crate) mod mem; diff --git a/oro-arch-x86_64/src/xfer.rs b/oro-arch-x86_64/src/xfer.rs index 86e50fc7..82fe2fd5 100644 --- a/oro-arch-x86_64/src/xfer.rs +++ b/oro-arch-x86_64/src/xfer.rs @@ -50,6 +50,10 @@ pub unsafe fn transfer( let core_id: u64 = transfer_token.core_id; let core_is_primary: u64 = u64::from(transfer_token.core_is_primary); + // Tell dbgutil we're about to switch + #[cfg(debug_assertions)] + crate::dbgutil::__oro_dbgutil_kernel_will_transfer(); + // Jump to stubs. // SAFETY(qix-): Do NOT use `ax`, `dx`, `cx` for transfer registers. asm!(