I am developing a Rust program to run on an embedded Linux board that is based on a 64-bit ARM processor. The embedded Linux for the target is built using Yocto (dunfell). My Rust development environment is Visual Studio Code running on Linux (Ubuntu). How can I set it up to do remote debugging of the program on the target board?
I expect the sequence would be something like:
The target board has a 64-bit ARM processor, so I want to use Rust to cross-compile for target aarch64-unknown-linux-gnu
.
I'm using Ubuntu 18.04 LTS (it is old, but I have to use it to support an old project built with an old Yocto version). I used apt
to install Ubuntu package gcc-8-aarch64-linux-gnu
. On a more recent Ubuntu perhaps I could install a more modern package such as gcc-11-aarch64-linux-gnu
.
In my ~/.cargo/config
:
[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc-8"
Then, I can manually use cargo
to cross-compile using the command:
cargo build --target=aarch64-unknown-linux-gnu
Then to cross-compile within VS Code — In my VS Code workspace for myapp, in .vscode/tasks.json
:
{
...
"tasks": [
...
{
"label": "rust: cargo build ARM"
"type": "cargo",
"command": "build",
"args": ["--target=aarch64-unknown-linux-gnu"],
"problemMatcher": [
"$rustc"
],
"group": "build",
},
]
}
Then I just do Shift-Ctrl-B, and select the "rust: cargo build ARM" build task.
The goal is to run myapp
on targetboard.local
as low-privileges user targetuser
(rather than root).
In VS Code, the CodeLLDB extension uses lldb to debug Rust programs. But, lldb is a large compilation in Yocto for the target hardware. But, it works fine to connect to gdbserver
running on the target board. The embedded Linux image running on the target board just needs to have gdbserver
on it.
The target board also needs to have an SSH server running on it, with support for either rsync
or plain SSH copy. rsync
is good because it can be faster to do the copy of the executable to the target.
In my VS Code workspace for myapp, in .vscode/launch.json
:
{
...
"configurations": [
...
{
"type": "lldb",
"request": "custom",
"name": "Remote executable 'myapp'",
"preLaunchTask": "rust: remote ARM debug setup",
"targetCreateCommands": ["target create ${workspaceFolder}/target/aarch64-unknown-linux-gnu/debug/myapp"],
"processCreateCommands": ["gdb-remote targetboard.local:17777"]
}
]
}
In my VS Code workspace for myapp, in .vscode/tasks.json
:
{
...
"tasks": [
...
{
"label": "rust: remote ARM debug setup",
"type": "shell",
"command": "${workspaceFolder}/scripts/remote_debug.sh",
"args": [ "${workspaceFolder}", "targetboard.local", "17777" ],
"group": "none",
"dependsOn": [
"rust: cargo build ARM",
],
},
]
}
In my VS Code workspace for myapp, I created the script scripts/remote_debug.sh
:
#!/bin/bash
VSCODE_WS="$1"
SSH_REMOTE="$2"
GDBPORT="$3"
APP="myapp"
TARGET_ARCH="aarch64-unknown-linux-gnu"
BUILD_BIN_FILE="${VSCODE_WS}/target/${TARGET_ARCH}/debug/${APP}"
TARGET_USER="targetuser"
TARGET_BIN_FILE="/home/targetuser/${APP}"
TARGET_CWD="/var/lib/myapp"
ssh "${TARGET_USER}@${SSH_REMOTE}" "killall gdbserver ${APP}"
if ! rsync -avz "${BUILD_BIN_FILE}" "${TARGET_USER}@${SSH_REMOTE}:${TARGET_BIN_FILE}"; then
# If rsync doesn't work, it may not be available on target. Fallback to trying SSH copy.
if ! scp "${BUILD_BIN_FILE}" "${TARGET_USER}@${SSH_REMOTE}:${TARGET_BIN_FILE}"; then
exit 2
fi
fi
ssh -f "${TARGET_USER}@${SSH_REMOTE}" "sh -c 'cd ${TARGET_CWD}; nohup gdbserver *:${GDBPORT} ${TARGET_BIN_FILE} > /dev/null 2>&1 &'"
The target CWD /var/lib/myapp
needs to exist with the right user permissions for targetuser
. I could just specify /home/targetuser
instead.
With that set up, I can just press F5 in VS Code, and it will compile, copy the file to the target board, and start remote-debugging it through gdbserver
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With