probe-rs / vscode

VSCode debug extension for probe-rs. It uses the MS DAP protocol to communicate directly with the probe (via probe-rs), and supports basic command line debugging in addition to VSCode UI.
https://probe.rs/
Other
66 stars 6 forks source link

VSCode `probe-rs` debugger extension "gets lost" single-stepping `embassy-rs` `wifi_blinky` app #106

Open U007D opened 1 month ago

U007D commented 1 month ago

Description

I am building and debugging (single-stepping) embassy's wifi_blinky example app.

I set two breakpoints: first is the first statement within main and the second is the first statement in the loop.

When using Step Over, everything appears to work correctly through the first loop iteration, but then the debugger appears to lose track of the remote processor starting with the second iteration of the loop. This only occurs when single-stepping (using Step Over). On the second iteration of the loop, the IDE starts by pointing to the second loop statement (control.gpio_set().await, skipping the info! statement). Single-stepping further gives more and more bizarre source code locations until the debugger simply displays "The editor could not be opened because the file was not found" and is unresponsive except for halt.

If I instead only use Continue, the debugger (and hardware) behave perfectly for as many iterations as I wish. Subsequently using Step Over shows the "lost control" behavior beginning with the subsequent iteration.

#[embassy_executor::main]
async fn main(spawner: Spawner) {
    let p = embassy_rp::init(Default::default()); // <-- breakpoint #1 here
    // let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin");
    // let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin");

    // To make flashing faster for development, you may want to flash the firmwares independently
    // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
    //     probe-rs download ../../cyw43-firmware/43439A0.bin --binary-format bin --chip RP2040 --base-address 0x10100000
    //     probe-rs download ../../cyw43-firmware/43439A0_clm.bin --binary-format bin --chip RP2040 --base-address 0x10140000
    let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) };
    let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };

    let pwr = Output::new(p.PIN_23, Level::Low);
    let cs = Output::new(p.PIN_25, Level::High);
    let mut pio = Pio::new(p.PIO0, Irqs);
    let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);

    static STATE: StaticCell<cyw43::State> = StaticCell::new();
    let state = STATE.init(cyw43::State::new());
    let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
    unwrap!(spawner.spawn(cyw43_task(runner)));

    control.init(clm).await;
    control
        .set_power_management(cyw43::PowerManagementMode::PowerSave)
        .await;

    let delay = Duration::from_secs(1);
    loop {
        info!("led on!"); // <-- breakpoint #2 here
        control.gpio_set(0, true).await;
        Timer::after(delay).await;

        info!("led off!");
        control.gpio_set(0, false).await;
        Timer::after(delay).await;
    }
}

Repro Steps

git clone https://github.com/embassy-rs/embassy
git checkout f7d372f33f3 # currently `HEAD`
cd embassy/examples/rp
cargo build --bin wifi_blinky --locked
code .
In VSCode, set a breakpoint on `main()`'s first statement and another on the `loop`'s first statement
Run and Debug | Ensure "launch executable on remote target using `probe_rs`" is selected | Start Debugging
Single step (to see error beginning on second loop iteration)
Continue (to pause at breakpoint successfully each iteration)

Perhaps I have misconfigured something?

Details

System: Apple M3 Max OS: macOS Sequoia 15.0.1 VSCode: Version: 1.94.2 Commit: 384ff7382de624fb94dbaf6da11977bba1ecd427 Date: 2024-10-09T16:08:44.566Z VSCode probe-rs Debugger Extension: Debugger for probe-rs v0.24.2 probe-rs --version: v0.24.0 (git commit: crates.io) rustc --version: rustc 1.82.0 (f6e511eec 2024-10-15) Debugger hardware: RPi Debug Probe Debugger firmware: v2.0.1 Target: RPi Pico W embassy-rs: commit rp2040.svd: pico-sdk v2.0.0

.vscode/launch.json

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "probe-rs-debug",
            "request": "launch",
            "name": "probe-rs (rp2040)",
            "cwd": "${workspaceFolder}",
            "connectUnderReset": true,
            "chip": "rp2040",
            "flashingConfig": {
                "flashingEnabled": true,
                "haltAfterReset": false
            },
            "coreConfigs": [
                {
                    "coreIndex": 0,
                    // Because `embassy` defiens multiple binaries in the `bin` folder, we can't just use the
                    // folder name as the executable name; hard-code the name of the bin we want to debug
                    //"programBinary": "./target/thumbv6m-none-eabi/debug/${workspaceFolderBasename}"
                    "programBinary": "./target/thumbv6m-none-eabi/debug/wifi_blinky"
                }
            ]
        },
        {
            "type": "probe-rs-debug",
            "request": "launch",
            "name": "launch executable on remote target using `probe_rs`",
            "cwd": "${workspaceFolder}",
            //!MODIFY (or remove)
            //"speed": 24000,
            //!MODIFY (or remove)
            // "probe": "VID:PID:<Serial>",
            "runtimeExecutable": "probe-rs",
            // "runtimeArgs": ["dap-server"],
            //!MODIFY
            "chip": "rp2040",
            "flashingConfig": {
                "flashingEnabled": true,
                "haltAfterReset": false,
                "formatOptions": {
                //!MODIFY (or remove). Valid values are: 'bin', 'hex', 'elf'(default), 'idf'
                // "binaryFormat": "elf"
                }
            },
            "coreConfigs": [
                {
                "coreIndex": 0,
                //!MODIFY
                "programBinary": "./target/thumbv6m-none-eabi/debug/wifi_blinky",
                //!MODIFY
                "svdFile": "./.vscode/rp2040.svd"
                }
            ],
            "env": {
                //!MODIFY (or remove)
                // If you set this variable, check the VSCode console log window for the location of the log file.
                "RUST_LOG": "info"
            },
                // Info, Debug
            "consoleLogLevel": "Console"
        }
    ]
}

Please let me know if there is any other information I can provide.

Jack-NimbleTron commented 7 hours ago

I apologize for the slow response on this one. The current version of probe-rs has some known limitations with respect to stepping code, and this one falls squarely into that category.

The debug stepping functionality is actually very tricky to implement, because the debug info generated by Rust (and similarly by other languages) have some limitations. Lots of optimizations to the current 'semantic' implementation is possible, but the only way to really fix this would be to implement platform specific disassembly to interpret the branching instructions in the code (this is what tools like gdb does).

For clarity's sake, I should add that you can 'workaround' this limitation by one of two means, or even a combination of the two:

I hope this helps.

PR's are always welcome :)