Skip to content

Commit

Permalink
dbgutil: initial addition of gdb debug suite
Browse files Browse the repository at this point in the history
  • Loading branch information
Qix- committed Jul 24, 2024
1 parent ebb8727 commit d2f385b
Show file tree
Hide file tree
Showing 19 changed files with 447 additions and 1 deletion.
11 changes: 11 additions & 0 deletions .github/workflows/push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,17 @@ jobs:
run: env RUSTFLAGS="-D warnings" RUSTDOCFLAGS="-D rustdoc::all" cargo doc --all-features --lib --target=oro-arch-x86_64/x86_64-unknown-oro.json -Zunstable-options -Zbuild-std=core,compiler_builtins,alloc -Zbuild-std-features=compiler-builtins-mem
- name: Lint (rustdoc - aarch64)
run: env RUSTFLAGS="-D warnings" RUSTDOCFLAGS="-D rustdoc::all" cargo doc --all-features --lib --target=oro-arch-aarch64/aarch64-unknown-oro.json -Zunstable-options -Zbuild-std=core,compiler_builtins,alloc -Zbuild-std-features=compiler-builtins-mem
lint-python:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Lint (python)
run: |
pip install black
black --check .
build-kernel-x86_64:
runs-on: ubuntu-latest
strategy:
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
/target/
__pycache__/
*.pyc
43 changes: 43 additions & 0 deletions dbgutil/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Oro kernel GDB debug utilities
This is a suite of GDB debugging utilities specifically for the Oro kernel.
They are automatically loaded when opening an Oro kernel variant in
`gdb`, a linux-based debugger.

The utilities help with debugging the Oro kernel via QEMU and performing
high-level operations such as printing the kernel's memory layout, performing
translations, and otherwise introspecting the kernel's state in a way that would
be manually tedious to do, or impossible to do with GDB alone.

Please note that these utilities are NOT intended to be used in production, and
are **SOLELY** for development-time debugging. Further, they are completely
Oro-specific and are not guaranteed to have any usefulness outside of the Oro
ecosystem.

## Usage
To use these utilities, simply open a debug profile variant of the Oro
kernel in GDB.

```shell
rust-gdb -q /path/to/oro-os/kernel/repo/target/x86_64-unknown-oro/debug/oro-kernel-x86_64
rust-gdb -q /path/to/oro-os/kernel/repo/target/aarch64-unknown-oro/debug/oro-kernel-aarch64
```

> [!IMPORTANT]
> GDB's auto-load functionality is whitelist-based, so by default the
> debug utilities will not load. You will need to add the following line to your
> `~/.gdbinit` file to enable auto-loading of the debug utilities:
>
> ```gdb
> add-auto-load-safe-path /path/to/oro-os/kernel/repo
> ```
> [!TIP]
> `gdb` typically only ships with the host architecture supported. It's recommended
> to build GDB from source with full support for all architectures.
>
> You can do this by running the following commands in the gdb source directory:
> ```shell
> ./configure --enable-targets=all --enable-tui --with-expat --with-python
> make -j$(nproc)
> sudo make install
> ```
206 changes: 206 additions & 0 deletions dbgutil/oro_debug_suite/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
import sys
import os
from os import path
import tempfile
import subprocess
import gdb

from .log import log
from .prompt import *

LIMINE_GIT_URL = "https://github.com/oro-os/limine.git"
LIMINE_REF = "v7.0.3-binary"


def print_logo():
"""
Print the ORO OS logo.
"""

log("")
log(" ⠀⠀⠀⠀⠀⠀⠀⣀⣤⣤⣤⣤⣤⣀⠔⠂⠉⠉⠑⡄")
log(" ⠀⠀⠀⠀⢠⣴⠟⠋⠉⠀⠀⠀⠉⠙⠻⣦⣀⣤⣤⣇")
log(" ⠀⠀⠀⣰⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⠟⠉⠉⢻⣧⠀ ORO OPERATING SYSTEM")
log(" ⠀⠀⢰⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣆⡀⢀⣸⡟⠀ kernel debug utilities")
log(" ⠀⠀⢸⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⠛⢻⡟⠋⠀⠀ github.com/oro-os/kernel")
log(" ⠀⠀⠸⣷⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⠊⠀⠀⣿⠃⠀⠀⠀ copyright (c) 2024, Josh Junon")
log(" ⠀⠀⡐⠹⣧⡀⠀⠀⠀⠀⠀⡠⠊⠀⠀⢀⣾⠏⠀⠀⠀⠀ MPL-2.0 License")
log(" ⠀⢰⠀⠀⠘⠻⣦⣄⣀⡔⠊⠀⣀⣠⣴⠟⠁")
log(" ⠀⠘⢄⣀⣀⠠⠔⠉⠛⠛⠛⠛⠛⠉")
log("")


def get_site_packages_dir():
"""
Returns the site-packages directory for the debug suite.
"""

site_dir = path.join(tempfile.gettempdir(), "oro_debug_suite_site_packages")
if not path.exists(site_dir):
os.mkdir(site_dir)

return site_dir


def check_bin_dep(name, *args):
"""
Checks to see if a singular binary dependency exists on the PATH.
Returns True if the binary exists, False otherwise.
"""

try:
subprocess.run(
[name, *args], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
log(f" found '{name}'")
except subprocess.CalledProcessError as e:
log(f" ! could not find '{name}' in PATH: {e}")
return False
return True


def check_bin_deps():
"""
Checks to see if all required binary dependencies exist on the PATH.
"""

log("checking for required binaries")
ok = True
ok = ok and check_bin_dep("git", "--version")
ok = ok and check_bin_dep("make", "--version")
return ok


def install_deps():
"""
Installs all pip dependencies for the debug suite.
The dependencies are installed into a temporary site-packages directory.
"""

log("python executable:", sys.executable)
site_dir = get_site_packages_dir()
log("using site-packages directory:", site_dir)
sys.path.append(site_dir)

requirements_txt = path.join(
path.dirname(path.dirname(__file__)), "requirements.txt"
)

if not path.exists(requirements_txt):
log("could not find requirements.txt; something is wrong with the debug suite")
log("please report this issue to the developers")
log("aborting suite bootstrap")
return

flag_file = path.join(site_dir, "deps_installed")

if path.exists(flag_file) and path.getmtime(flag_file) > path.getmtime(
requirements_txt
):
# Skipping installation of dependencies
return

log("installing dependencies")

pip_environ = os.environ.copy()
pip_environ["PIP_TARGET"] = site_dir

subprocess.run(
[
sys.executable,
"-m",
"pip",
"install",
"--disable-pip-version-check",
"--no-python-version-warning",
"-I",
"--no-input",
"-r",
requirements_txt,
],
check=True,
env=pip_environ,
)

with open(flag_file, "w") as f:
f.write("")

log("dependencies installed")


def fetch_limine():
"""
Fetches the limine bootloader from the Oro repositories
and builds the limine utility.
"""

limine_dir = path.join(get_site_packages_dir(), "limine")
limine_flag = f"{limine_dir}.version"

if path.exists(limine_flag):
with open(limine_flag, "r") as f:
if f.read().strip() == LIMINE_REF:
log("limine at correct version; skipping fetch")
return
else:
log("limine version mismatch; re-fetching")
os.remove(limine_flag)
else:
log("fetching limine bootloader version", LIMINE_REF)

if path.exists(limine_dir):
import shutil

log("removing existing limine directory")
shutil.rmtree(limine_dir)

subprocess.run(
[
"git",
"clone",
"--depth=1",
"-c",
"advice.detachedHead=false",
"--branch",
LIMINE_REF,
LIMINE_GIT_URL,
limine_dir,
],
check=True,
)

log("limine fetched; building utility")

subprocess.run(
["make", "-C", limine_dir, "limine"],
check=True,
)

log("limine built")

with open(limine_flag, "w") as f:
f.write(LIMINE_REF)


def bootstrap_debug_suite():
"""
Sets up all pre-requisites for the debug suite
and registers all necessary hooks with GDB.
"""

print_logo()

if not check_bin_deps():
log(
"missing one or more required binaries on the PATH; aborting suite bootstrap"
)
log("please ensure that the stated binaries are available and restart GDB")
return

fetch_limine()
install_deps()


bootstrap_debug_suite()
5 changes: 5 additions & 0 deletions dbgutil/oro_debug_suite/log.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
def log(*args, **kwargs):
"""
Oro-branded logging function.
"""
print("\x1b[38;5;129moro\x1b[m", *args, **kwargs)
12 changes: 12 additions & 0 deletions dbgutil/oro_debug_suite/prompt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import gdb


def gdb_prompt(old_prompt):
"""
Custom GDB prompt.
"""

return "(oro) "


gdb.prompt_hook = gdb_prompt
2 changes: 2 additions & 0 deletions dbgutil/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pycdlib==1.14.0
kiwisolver==1.4.5
5 changes: 5 additions & 0 deletions oro-arch-aarch64/arch.x
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
SECTIONS {
.text : {
KEEP(*(.text.force_keep .text.force_keep.*));
} :text
}
2 changes: 2 additions & 0 deletions oro-arch-aarch64/preboot.x
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ SECTIONS {
_ORO_STUBS_LEN = . - _ORO_STUBS_START;
} :text
}

INCLUDE "oro-arch-aarch64/arch.x"
8 changes: 8 additions & 0 deletions oro-arch-aarch64/src/arch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ unsafe impl Arch for Aarch64 {
pl011::StopBits::One,
pl011::Parity::None,
));

// XXX DEBUG
oro_common::dbg!(
Self,
"debug",
"{:#?}",
crate::reg::sctlr_el1::SctlrEl1::load()
);
}

unsafe fn init_local() {
Expand Down
5 changes: 5 additions & 0 deletions oro-arch-x86_64/arch.x
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
SECTIONS {
.text : {
KEEP(*(.text.force_keep .text.force_keep.*));
} :text
}
2 changes: 2 additions & 0 deletions oro-arch-x86_64/preboot.x
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ SECTIONS {
_ORO_STUBS_LEN = . - _ORO_STUBS_START;
} :text
}

INCLUDE "oro-arch-x86_64/arch.x"
4 changes: 4 additions & 0 deletions oro-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ license = "MPL-2.0"
[lib]
doctest = false

[features]
default = []
dbgutil = []

[dependencies]
oro-common-proc.workspace = true
static_assertions.workspace = true
Loading

0 comments on commit d2f385b

Please sign in to comment.