Skip to content

Commit c53dea5

Browse files
committed
Add doc: debugging contract
1 parent 9c2d194 commit c53dea5

File tree

1 file changed

+149
-0
lines changed

1 file changed

+149
-0
lines changed

workspace/docs/debugging_contract.md

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
Here's the polished version:
2+
3+
# Debugging Contract
4+
5+
## Native Simulator Debugging
6+
7+
By running `make generate`, a Rust contract is created with a `-dbg` suffix in the contract directory. This project allows you to compile the contract as a native platform dynamic library. To build it, simply run `make build-simulator`. Afterward, you can insert breakpoints and debug the contract code by enabling the `simulator` feature of `ckb-testtool` in unit tests.
8+
9+
## Debugging with ckb-debugger and VSCode
10+
11+
An alternative debugging method is available using `ckb-debugger` (in this case, with VSCode). `ckb-debugger` operates as a `gdb server`, supporting both gdb and lldb-18. In VSCode, the [Native Debug](https://marketplace.visualstudio.com/items?itemName=webfreak.debug) extension supports remote gdb debugging, which you'll need for this setup.
12+
* Note: Although CodeLLDB supports remote debugging, it does not work well here due to the use of lldb version 17.
13+
14+
### Compilation
15+
16+
By default, the compiled output lacks debug symbols due to size constraints, so you need to compile using the `profile.ckb-debug` profile. You'll also need to create a copy of the binary for gdb/llvm debugging and strip the symbols from the original file for `ckb-debugger` to run.
17+
18+
```shell
19+
make build MODE=ckb-debug CARGO_ARGS='--profile=ckb-debug'
20+
cp build/ckb-debug/<Contract-Name> build/ckb-debug/<Contract-Name>.debug
21+
llvm-objcopy --strip-debug --strip-all build/ckb-debug/<Contract-Name>
22+
```
23+
24+
To configure `tasks.json` in VSCode (using `c1` from CI as an example):
25+
26+
```json
27+
{
28+
"label": "Build Debug",
29+
"type": "shell",
30+
"command": "make build MODE=ckb-debug CARGO_ARGS='--profile=ckb-debug' && cp build/ckb-debug/c1 build/ckb-debug/c1.debug && llvm-objcopy --strip-debug --strip-all build/ckb-debug/c1"
31+
},
32+
```
33+
34+
#### Running ckb-debugger
35+
36+
(You can skip this section if the contract you are debugging doesn’t require transaction information.)
37+
38+
Typically, contracts need transaction data, which can be retrieved from unit tests. Add the following code before `context.verify_tx(&tx, MAX_CYCLES)` in your unit tests:
39+
40+
```rust
41+
let tx_data = context.dump_tx(&tx).expect("dump tx info");
42+
std::fs::write(
43+
"tx.json",
44+
serde_json::to_string_pretty(&tx_data).expect("json"),
45+
)
46+
.expect("write tx");
47+
```
48+
49+
Then, start `ckb-debugger` with:
50+
51+
```shell
52+
ckb-debugger \
53+
--bin=build/ckb-debug/c1 \
54+
--mode=gdb_gdbstub \
55+
--gdb-listen=0.0.0.0:8000 \
56+
--tx-file=tests/tx.json \
57+
-s=lock \
58+
-i=0
59+
```
60+
* The example uses port 8000; feel free to change it if necessary.
61+
* Adjust `-s` and `-i` according to your contract's needs.
62+
63+
You can configure `tasks.json` in VSCode to automatically start `ckb-debugger`:
64+
65+
```json
66+
{
67+
"label": "Debug c1",
68+
"isBackground": true,
69+
"type": "process",
70+
"command": "ckb-debugger",
71+
"args": [
72+
"--bin=build/ckb-debug/c1",
73+
"--mode=gdb_gdbstub",
74+
"--gdb-listen=0.0.0.0:8000",
75+
"--tx-file=tests/tx.json",
76+
"-s=lock",
77+
"-i=0"
78+
],
79+
"options": {
80+
"cwd": "${workspaceRoot}"
81+
},
82+
},
83+
```
84+
* The `isBackground` setting ensures the task runs in the background and doesn't terminate during debugging.
85+
86+
Since `ckb-debugger` doesn’t exit automatically after debugging, you'll need to configure a task to stop it:
87+
88+
```json
89+
{
90+
"label": "stop-ckb-debugger",
91+
"type": "shell",
92+
"command": "killall ckb-debugger || true"
93+
},
94+
```
95+
96+
#### GDB Debugging
97+
98+
```shell
99+
gdb build/ckb-debug/c1.debug
100+
```
101+
Then connect to `ckb-debugger`'s gdb server:
102+
103+
```shell
104+
target remote 127.0.0.1:8000
105+
```
106+
Once connected, you can debug using standard GDB commands.
107+
108+
#### LLDB Debugging
109+
110+
* Ensure you are using lldb version 18 or later.
111+
112+
```shell
113+
lldb build/ckb-debugger/c1.debug
114+
```
115+
Then connect to `ckb-debugger`'s gdb server (you can omit the local address and just use the port):
116+
117+
```shell
118+
gdb-remote 8000
119+
```
120+
After connecting, you can use standard LLDB commands to debug.
121+
122+
#### VSCode Debugging
123+
124+
* GDB must be installed.
125+
* The Native Debug extension is required for debugging in VSCode.
126+
127+
First, configure `tasks.json` as described above. Then, set up your `launch.json` for debugging:
128+
129+
```json
130+
{
131+
"name": "GDB",
132+
"type": "gdb",
133+
"request": "attach",
134+
"executable": "build/ckb-debug/c1.debug",
135+
"debugger_args": [],
136+
"cwd": "${workspaceRoot}",
137+
"remote": true,
138+
"target": "127.0.0.1:8000",
139+
"preLaunchTask": "Debug c1",
140+
"postDebugTask": "stop-ckb-debugger"
141+
}
142+
```
143+
After launching the debugger, you can set breakpoints and inspect variables as usual.
144+
145+
### Additional Notes
146+
147+
* The Native Simulator method is more convenient and supports advanced debugging features, which may not be available with `ckb-debugger`.
148+
* `ckb-debugger` provides a debugging environment closer to the contract's runtime environment, while the Native Simulator only emulates the online environment.
149+
* `ckb-debugger` may perform poorly compared to the Native Simulator, especially on low-end computers.

0 commit comments

Comments
 (0)