Claude-skill-registry gdb-attach
Use when debugging the Breenix kernel at assembly or C-level using GDB - investigating CPU exceptions, page faults, triple faults, examining register state during interrupt handling, stepping through boot sequence, analyzing syscall entry/exit paths, debugging context switches, or inspecting memory layout and page tables.
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/gdb-attach" ~/.claude/skills/majiayu000-claude-skill-registry-gdb-attach && rm -rf "$T"
skills/data/gdb-attach/SKILL.mdBreenix GDB Debugging
When to Use This Skill
Use this skill when you need to debug the Breenix kernel at the assembly or C-level using GDB. Common scenarios:
- Investigating CPU exceptions, page faults, or triple faults
- Examining register state during interrupt handling
- Stepping through boot sequence or early initialization
- Analyzing syscall entry/exit paths
- Debugging context switches and process state transitions
- Inspecting memory layout and page tables
- Understanding TSC/APIC timer behavior
Quick Start
1. Launch QEMU in GDB Mode
# Set the GDB flag and run the kernel BREENIX_GDB=1 cargo run --release --bin qemu-uefi
This will:
- Start QEMU with
(GDB server on localhost:1234, paused)-s -S - Wait for GDB to connect before executing any code
- Print connection instructions
2. Connect GDB (in another terminal)
# Connect to the running QEMU instance gdb target/x86_64-breenix/release/kernel -ex 'target remote localhost:1234'
Or use the helper command from
.gdbinit:
gdb target/x86_64-breenix/release/kernel (gdb) breenix-connect
Essential GDB Commands for Kernel Debugging
Navigation & Execution
# Continue execution c # Step one instruction (into calls) si # Step one instruction (over calls) ni # Step one source line s # Step over source line n # Finish current function finish
Breakpoints
# Hardware breakpoint (works before paging is set up) hbreak kernel_main # Software breakpoint (requires memory to be mapped) break rust_syscall_handler break timer_interrupt_handler break process::manager::spawn_process # Conditional breakpoint break syscall_handler if $rax == 0x1 # Only break on specific syscall # List breakpoints info breakpoints # Delete breakpoint delete 1
Registers & State
# Show all general-purpose registers info registers # Show specific register print $rip print/x $rsp print/x $cr3 # Show segment registers info registers cs ds ss fs gs # Custom helper to show segments nicely show-segments
Memory Inspection
# Examine memory (format: x/nfu addr) # n=count, f=format (x=hex, d=decimal, s=string), u=unit (b=byte, h=halfword, w=word, g=giant/8-bytes) x/16xg $rsp # Show 16 8-byte values at stack pointer x/32xb 0xffff800000000000 # Show 32 bytes at kernel base x/s 0xsomeaddr # Show null-terminated string x/i $rip # Show instruction at program counter # Display memory continuously as you step display/16xg $rsp
Backtraces & Frames
# Show call stack backtrace bt # Show detailed backtrace with local variables backtrace full # Move between stack frames frame 0 frame 1 # Show local variables in current frame info locals # Show function arguments info args
Symbols & Source
# List source code around current location list # Show disassembly around current instruction disassemble # Show disassembly of specific function disassemble kernel_main disassemble rust_syscall_handler # Show type information ptype some_variable
Common Debugging Scenarios
Scenario 1: Boot Debugging
Set breakpoint at kernel entry and step through initialization:
(gdb) hbreak kernel_main (gdb) c (gdb) layout asm # Show assembly view (gdb) si # Step through boot sequence (gdb) info registers
Scenario 2: Syscall Debugging
Debug a specific syscall (e.g., clock_gettime):
(gdb) break rust_syscall_handler (gdb) c # When syscall hits: (gdb) print/x $rax # Syscall number (gdb) print/x $rdi # First argument (gdb) print/x $rsi # Second argument (gdb) s # Step into handler
Scenario 3: Page Fault Investigation
Examine CPU state on page fault:
(gdb) break page_fault_handler (gdb) c # When fault occurs: (gdb) print/x $cr2 # Faulting address (gdb) print/x $rip # Instruction that faulted (gdb) x/i $rip # Show the faulting instruction (gdb) print error_code # Error code (if captured) (gdb) backtrace
Scenario 4: Timer Interrupt Debugging
Trace timer interrupt flow:
(gdb) break timer_interrupt_handler (gdb) c # First timer interrupt hits: (gdb) print ticks # Check tick counter (gdb) s # Step into APIC EOI (gdb) finish # Return from handler (gdb) c # Continue to next tick
Scenario 5: Context Switch Analysis
Debug process switching:
(gdb) break context_switch::switch_to (gdb) c # When switching: (gdb) print from_process (gdb) print to_process (gdb) print/x $cr3 # Current page table (gdb) s # Step through switch (gdb) print/x $cr3 # New page table
Breenix-Specific Helpers
The
.gdbinit file provides custom commands:
# Connect to QEMU breenix-connect # Show segment registers nicely show-segments # Set common kernel breakpoints breenix-breaks
Advanced Techniques
Watchpoints (Memory Access Breakpoints)
# Break when memory location is written watch *0xffff800000010000 # Break when memory location is read rwatch some_global_variable # Break on read or write awatch some_global_variable
Examining Page Tables
# Get CR3 (page table root) print/x $cr3 # Walk page table manually (requires understanding x86_64 paging) x/4xg ($cr3 & ~0xfff) # PML4 entries
TSC Debugging
# Read TSC register value print $ia32_tsc # May not be directly accessible # Instead, examine TSC handling code: break tsc::read_tsc
Tips & Gotchas
- Use hardware breakpoints early: Before paging is fully set up, use
instead ofhbreakbreak - Serial output interference: GDB traffic and serial logs both compete for terminal output
- Optimization can confuse stepping: Release builds may inline or reorder code
- No symbols for assembly: Some early boot code won't have Rust symbols
- Context switches reset state: Watch out for process switching changing $cr3, $rsp, etc.
Exiting GDB
# Quit GDB (QEMU will also stop) quit # Detach but leave QEMU running detach
Integration with Existing Workflow
This GDB debugging flow complements the existing log-based debugging:
- Use logs for: High-level flow, timing issues, multi-test scenarios
- Use GDB for: Precise state inspection, assembly-level debugging, crash analysis
You can combine both: run with logs first to narrow down the issue, then use GDB to investigate the exact instruction or register state.