{"record":{"id":"fd2a06bcf75364c0","repo":"firecracker-microvm/firecracker","slug":"error-getting-initial-gdb-event","errorCode":null,"errorMessage":"Error getting initial gdb event","messagePattern":"Error getting initial gdb event","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/vmm/src/gdb/event_loop.rs","lineNumber":35,"sourceCode":"use crate::Vmm;\nuse crate::logger::{error, trace};\n\n/// Starts the GDB event loop which acts as a proxy between the Vcpus and GDB\npub fn event_loop(\n    connection: UnixStream,\n    vmm: Arc<Mutex<Vmm>>,\n    gdb_event_receiver: Receiver<usize>,\n    entry_addr: GuestAddress,\n) {\n    let target = FirecrackerTarget::new(vmm, gdb_event_receiver, entry_addr);\n    let connection: Box<dyn ConnectionExt<Error = std::io::Error>> = { Box::new(connection) };\n    let debugger = GdbStub::new(connection);\n\n    // We wait for the VM to reach the inital breakpoint we inserted before starting the event loop\n    target\n        .gdb_event\n        .recv()\n        .expect(\"Error getting initial gdb event\");\n\n    gdb_event_loop_thread(debugger, target);\n}\n\nstruct GdbBlockingEventLoop {}\n\nimpl run_blocking::BlockingEventLoop for GdbBlockingEventLoop {\n    type Target = FirecrackerTarget;\n    type Connection = Box<dyn ConnectionExt<Error = std::io::Error>>;\n\n    type StopReason = MultiThreadStopReason<u64>;\n\n    /// Poll for events from either Vcpu's or packets from the GDB connection\n    fn wait_for_stop_reason(\n        target: &mut FirecrackerTarget,\n        conn: &mut Self::Connection,\n    ) -> Result<\n        run_blocking::Event<MultiThreadStopReason<u64>>,","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/firecracker-microvm/firecracker/blob/0a745def42ddf4cc2a744d79a08a27ff50b5d27a/src/vmm/src/gdb/event_loop.rs#L17-L53","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the entry-point address configured for GDB actually matches the guest kernel entry that vcpu 0 will reach","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","Replace the expect with graceful handling: on Err, log and bail out of the gdb loop instead of panicking","Check vcpu thread logs for an earlier panic that dropped the sender"],"exampleFix":"// before\ntarget\n    .gdb_event\n    .recv()\n    .expect(\"Error getting initial gdb event\");\n\n// after\nif target.gdb_event.recv().is_err() {\n    warn!(\"gdb: vcpu sender dropped before the initial breakpoint event\");\n    return;\n}","handlingStrategy":"validation","validationCode":"// Before gdb_thread blocks on recv(): make sure vcpus are running and the entry bp is installed\n{\n    let vmm = vmm.lock().unwrap();\n    assert!(!vmm.vm.as_kvm().unwrap().vcpus_handles().is_empty(),\n        \"no running vcpus to hit the entry breakpoint\");\n}\n// guest entry must be reachable: validate entry_addr against the kernel image/boot flow","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set entry_addr from the same source the vcpu boot path uses (kernel entry point), never a hardcoded guess","Do not stop the microvm between gdb socket setup and the first breakpoint hit","Watch vcpu thread logs: a dropped sender usually means the vcpu panicked or exited first"],"tags":["rust","panic","gdb","channel","breakpoint","firecracker"],"backgroundTag":"channel-sender-disconnected","analyzedSha":"0a745def42ddf4cc2a744d79a08a27ff50b5d27a","analyzedAt":"2026-08-19T05:27:02.517Z","contentChangedAt":"2026-08-19T05:27:02.517Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}