# Debugging Contracts with VSCode The `ckb-debugger` provides a gdb-server mode for contract debugging. In VSCode, this requires the [Native Debug](https://marketplace.visualstudio.com/items?itemName=webfreak.debug) extension to connect to `ckb-debugger`'s gdb-server for debugging. * **Note:** While CodeLLDB supports remote debugging, it does not work well in this case due to its use of `LLDB` version 17. ## Compile The compiled contract must include the appropriate symbol files for debugging. For C, add `-g`; for Rust, set `strip = false` and `debug = true` in the `profile` section. After compiling, since binaries with symbol files tend to be large, you need to process them with `llvm-objcopy`: ```shell cp build/ckb-debug/ build/ckb-debug/.debug llvm-objcopy --strip-debug --strip-all build/ckb-debug/ ``` To configure `tasks.json` in VSCode (using the `c1` contract as an example): ```json { "label": "Build Debug", "type": "shell", "command": "make build && cp build/ckb-debug/c1 build/ckb-debug/c1.debug && llvm-objcopy --strip-debug --strip-all build/ckb-debug/c1" } ``` ### Running `ckb-debugger` (Skip this section if the contract you're debugging doesn't require transaction information.) Typically, contracts require transaction data, which can be extracted from unit tests using the [dump_tx](https://github.com/nervosnetwork/ckb-testtool/blob/41c76ed2aef128fdf6e7e73b61d1bfa45e02b005/src/context.rs#L573) function. Add the following code before `context.verify_tx(&tx, MAX_CYCLES)` in your unit tests: ```rust let tx_data = context.dump_tx(&tx).expect("dump tx info"); std::fs::write( "tx.json", serde_json::to_string_pretty(&tx_data).expect("json"), ).expect("write tx"); ``` Then start `ckb-debugger` with: ```shell ckb-debugger \ --bin=build/ckb-debug/c1 \ --mode=gdb_gdbstub \ --gdb-listen=0.0.0.0:8000 \ --tx-file=tests/tx.json \ -s=lock \ -i=0 ``` * This example uses port 8000, but feel free to change it if needed. * Adjust `-s` and `-i` according to your contract’s requirements. You can configure `tasks.json` in VSCode to automatically start `ckb-debugger`: ```json { "label": "Debug c1", "isBackground": true, "type": "process", "command": "ckb-debugger", "args": [ "--bin=build/ckb-debug/c1", "--mode=gdb_gdbstub", "--gdb-listen=0.0.0.0:8000", "--tx-file=tests/tx.json", "-s=lock", "-i=0" ], "options": { "cwd": "${workspaceRoot}" } } ``` * The `isBackground` setting ensures the task runs in the background and stays active during debugging. Since `ckb-debugger` doesn’t automatically exit after debugging, you'll need a task to stop it: ```json { "label": "stop-ckb-debugger", "type": "shell", "command": "killall ckb-debugger || true" } ``` ### GDB Debugging ```shell gdb build/ckb-debug/c1.debug ``` Then connect to `ckb-debugger`'s GDB server: ```shell target remote 127.0.0.1:8000 ``` Once connected, you can debug using standard GDB commands. ### LLDB Debugging * Ensure you are using LLDB version 18 or later. ```shell lldb build/ckb-debugger/c1.debug ``` Then connect to `ckb-debugger`'s GDB server (you can omit the local address and just use the port): ```shell gdb-remote 8000 ``` After connecting, use standard LLDB commands for debugging. ### VSCode Debugging * GDB must be installed. * The Native Debug extension is required for debugging in VSCode. First, configure `tasks.json` as described above. Then set up your `launch.json` for debugging: ```json { "name": "GDB", "type": "gdb", "request": "attach", "executable": "build/ckb-debug/c1.debug", "debugger_args": [], "cwd": "${workspaceRoot}", "remote": true, "target": "127.0.0.1:8000", "preLaunchTask": "Debug c1", "postDebugTask": "stop-ckb-debugger" } ``` After launching the debugger, you can set breakpoints and inspect variables as usual.