firecracker-microvm/firecracker · error

Error getting initial gdb event

Error message

Error getting initial gdb event

What it means

Panic in `run_gdb_event_loop` (event_loop.rs:35): `target.gdb_event.recv().expect("Error getting initial gdb event")` fails because `recv()` returned Err, which on a crossbeam/std channel means every sender was dropped — the vcpu that should report hitting the entry-point hardware breakpoint exited (or panicked) before ever sending the initial debug event.

Source

Thrown at src/vmm/src/gdb/event_loop.rs:35

use crate::Vmm;
use crate::logger::{error, trace};

/// Starts the GDB event loop which acts as a proxy between the Vcpus and GDB
pub fn event_loop(
    connection: UnixStream,
    vmm: Arc<Mutex<Vmm>>,
    gdb_event_receiver: Receiver<usize>,
    entry_addr: GuestAddress,
) {
    let target = FirecrackerTarget::new(vmm, gdb_event_receiver, entry_addr);
    let connection: Box<dyn ConnectionExt<Error = std::io::Error>> = { Box::new(connection) };
    let debugger = GdbStub::new(connection);

    // We wait for the VM to reach the inital breakpoint we inserted before starting the event loop
    target
        .gdb_event
        .recv()
        .expect("Error getting initial gdb event");

    gdb_event_loop_thread(debugger, target);
}

struct GdbBlockingEventLoop {}

impl run_blocking::BlockingEventLoop for GdbBlockingEventLoop {
    type Target = FirecrackerTarget;
    type Connection = Box<dyn ConnectionExt<Error = std::io::Error>>;

    type StopReason = MultiThreadStopReason<u64>;

    /// Poll for events from either Vcpu's or packets from the GDB connection
    fn wait_for_stop_reason(
        target: &mut FirecrackerTarget,
        conn: &mut Self::Connection,
    ) -> Result<
        run_blocking::Event<MultiThreadStopReason<u64>>,

View on GitHub (pinned to 0a745def42)

Solutions

  1. Verify the entry-point address configured for GDB actually matches the guest kernel entry that vcpu 0 will reach
  2. Ensure the VM is started (vcpus running) after gdb_thread installs the entry breakpoint — do not stop the VM before the initial breakpoint is hit
  3. Replace the expect with graceful handling: on Err, log and bail out of the gdb loop instead of panicking
  4. Check vcpu thread logs for an earlier panic that dropped the sender

Example fix

// before
target
    .gdb_event
    .recv()
    .expect("Error getting initial gdb event");

// after
if target.gdb_event.recv().is_err() {
    warn!("gdb: vcpu sender dropped before the initial breakpoint event");
    return;
}
Defensive patterns

Strategy: validation

Validate before calling

// Before gdb_thread blocks on recv(): make sure vcpus are running and the entry bp is installed
{
    let vmm = vmm.lock().unwrap();
    assert!(!vmm.vm.as_kvm().unwrap().vcpus_handles().is_empty(),
        "no running vcpus to hit the entry breakpoint");
}
// guest entry must be reachable: validate entry_addr against the kernel image/boot flow

Prevention

When it happens

Trigger: GDB configured, `gdb_thread` sets a hw breakpoint at `entry_addr` and blocks on the channel; the vcpu sender is destroyed before sending — e.g. VM is stopped/killed first, the vcpu thread panics, or the guest never reaches entry_addr before the process tears down and the sender is dropped.

Common situations: Wrong `entry_addr` passed to the GDB config so the breakpoint is never hit while the sender lifetime ends at shutdown; microvm configured to pause/exit immediately; race between `StopMicrovm`/shutdown and the gdb handshake; vcpu thread crash before first debug exit.

Related errors


AI-assisted analysis of firecracker-microvm/firecracker@0a745def42 (2026-08-19). Data as JSON: /api/errors/fd2a06bcf75364c0. Report an issue: GitHub.