Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions tests/Rpi4/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,63 @@ Check Rpi4 pin out here (Alt4): https://pinout.xyz/pinout/jtag<br>
| RTCK | 11 | GPIO 23 |
| TDO | 13 | GPIO 24 |
| GND | 18 | Any Ground |

# Userspace debugging with gdbserver + Seer

The image ships `gdbserver` and the `recursive-test` package, which installs
`/usr/bin/math_toolkit` (the `../recursive_test` C++ program). It is built
**statically, non-PIE, `-g -O0`, unstripped** on purpose: with no shared
libraries and a fixed load address, remote debugging needs no sysroot, no
shared-library relocation, and behaves identically in launch and `--attach`
modes - which sidesteps the GDB-15-host / gdbserver-12-target `lmid`
incompatibility in the svr4 library list.

After a build, `debug-rpi4/` holds the matching unstripped binary plus the
exact source tree the binary was compiled from. The on-Pi
`/usr/bin/math_toolkit` and `debug-rpi4/math_toolkit` are byte-identical
(check with `sha256sum`) - keep them in sync after every rebuild.

### On the Raspberry Pi

Connect the Pi's Ethernet and reach it over the network (see the IP section
above; default LAN is `192.168.1.1`). Then, launch mode:

```
ssh root@<pi-ip>
gdbserver --once :2345 /usr/bin/math_toolkit
```

or attach mode (program already running):

```
math_toolkit &
gdbserver --once --attach :2345 $(pidof math_toolkit)
```

`--once` makes gdbserver exit cleanly when the session ends; re-run it before
each new session.

### On the host

```
seergdb --gdb-program gdb-multiarch \
--connect <pi-ip>:2345 \
--sym /abs/path/tests/Rpi4/debug-rpi4/math_toolkit \
/abs/path/tests/Rpi4/debug-rpi4/math_toolkit
```

In Seer's gdb command list (Settings -> Configuration) or `~/.gdbinit`, before
connecting:

```
set architecture aarch64
set remotetimeout 60
set mi-async on
set non-stop off
set substitute-path /workdir/openwrt/build_dir/target-aarch64_cortex-a72_musl/recursive-test-1.0 /abs/path/tests/Rpi4/debug-rpi4
```

Set a breakpoint (`break factorial(int)`, `break main`), press **Continue**
(not Interrupt - Interrupt only does something once the program is running).
`math_toolkit` loops every 2 s, so breakpoints in `factorial` / `fibonacci`
hit repeatedly.
48 changes: 38 additions & 10 deletions tests/Rpi4/build_Rpi4_owrt.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# Script to build OpenWrt image for Raspberry Pi 4 with debug symbols
# Assumes OpenWrt build environment is set up (docker)
# I have tested with kernel version 6.15 but vmlinux symbol file is optimized out so feature Debug on init can't be
# I have tested with kernel version 6.15 but vmlinux symbol file is optimized out so feature Debug on init can't be
# performed with kernel v6.15
# It is recommended to use Linux kernel version 5.15

Expand All @@ -16,7 +16,7 @@ git config --global http.maxRequestBuffer 100M
git config --global http.version HTTP/1.1
git config --global http.maxRequests 100
git config --global core.compression 0
git config --global --unset http.proxy
git config --global --unset http.proxy
git config --global --unset https.proxy
# Define variables
TOPDIR=$PWD
Expand Down Expand Up @@ -49,6 +49,19 @@ echo "Updating feeds..."
./scripts/feeds update -a
./scripts/feeds install -a

# Add out-of-tree packages BEFORE any "make defconfig": defconfig silently drops
# CONFIG_PACKAGE_* entries for packages that are not yet present in the tree, so
# these must be copied in first or they never get built.
# hello world kernel module
rm -rf $HELLO_WORLD_DIR/helloworld
cp -rfT $TOPDIR/helloworld_owrt $HELLO_WORLD_DIR/helloworld
# myplatform kernel module
rm -rf $HELLO_WORLD_DIR/myplatform
cp -rfT $TOPDIR/myplatform_owrt $HELLO_WORLD_DIR/myplatform
# recursive-test userspace program (math_toolkit) for gdbserver + Seer
rm -rf $OPENWRT_DIR/package/utils/recursive-test
cp -rfT $TOPDIR/recursive_test_owrt $OPENWRT_DIR/package/utils/recursive-test

# Step 3: Configure OpenWrt for Raspberry Pi 4
echo "Configuring OpenWrt for Raspberry Pi 4..."
make defconfig
Expand All @@ -67,6 +80,9 @@ CONFIG_KALLSYMS_ALL=y
CONFIG_DEBUG_KERNEL=y
CONFIG_PACKAGE_kmod-helloworld=y
CONFIG_PACKAGE_kmod-myplatform=y
CONFIG_PACKAGE_iptables-nft=y
CONFIG_PACKAGE_gdbserver=y
CONFIG_PACKAGE_recursive-test=y
EOF
make defconfig

Expand All @@ -81,16 +97,25 @@ echo 'CONFIG_KALLSYMS_ALL=y' >> .config
echo 'CONFIG_DEBUG_KERNEL=y' >> .config
echo 'CONFIG_PACKAGE_kmod-helloworld=y' >> .config
echo 'CONFIG_PACKAGE_kmod-myplatform=y' >> .config
echo 'CONFIG_PACKAGE_iptables-nft=y' >> .config
echo 'CONFIG_PACKAGE_gdbserver=y' >> .config
echo 'CONFIG_PACKAGE_recursive-test=y' >> .config
echo 'CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=n' >> .config

sed -i 's|CONFIG_KERNEL_DEBUG_INFO_REDUCED=y|CONFIG_KERNEL_DEBUG_INFO_REDUCED=n|g' .config

# add hello world module
rm -rf $HELLO_WORLD_DIR/helloworld
cp -rfT $TOPDIR/helloworld_owrt $HELLO_WORLD_DIR/helloworld
# add myplatform module
rm -rf $HELLO_WORLD_DIR/myplatform
cp -rfT $TOPDIR/myplatform_owrt $HELLO_WORLD_DIR/myplatform
# Resolve dependencies for every option appended above (iptables-nft pulls in
# kmod-nft-core / xtables-nft / kmod-ipt-core, etc.). Without this opkg fails
# package/install with "cannot find dependency ...".
make defconfig

# Confirm the out-of-tree packages survived dependency resolution.
grep -q '^CONFIG_PACKAGE_recursive-test=y' .config || { echo_red "recursive-test missing from .config"; exit 1; }

# Force recursive-test to rebuild even when only its compile recipe changed
# (OpenWrt's build stamp does not track the recipe text).
make package/recursive-test/clean V=s || true

# Path config.txt
cp -f $TOPDIR/patches/config.txt $TOPDIR/openwrt/target/linux/bcm27xx/image/config.txt
# Apply patched DTS with myplatform node
Expand All @@ -105,14 +130,17 @@ sed -i 's|# CONFIG_KALLSYMS_ALL is not set|CONFIG_KALLSYMS_ALL=y|g' \
$OPENWRT_DIR/build_dir/target-aarch64_cortex-a72_musl/linux-bcm27xx_bcm2711/linux-5.15.132/.config
echo 'CONFIG_IKCONFIG_PROC=y' >> $OPENWRT_DIR/build_dir/target-aarch64_cortex-a72_musl/linux-bcm27xx_bcm2711/linux-5.15.132/.config
echo 'CONFIG_CORESIGHT_CPU_DEBUG=y' >> $OPENWRT_DIR/build_dir/target-aarch64_cortex-a72_musl/linux-bcm27xx_bcm2711/linux-5.15.132/.config
sed -i 's|# CONFIG_GDB_SCRIPTS is not set|CONFIG_GDB_SCRIPTS=y|g' \
$OPENWRT_DIR/build_dir/target-aarch64_cortex-a72_musl/linux-bcm27xx_bcm2711/linux-5.15.132/.config

sed -i 's|MAKEFLAGS += -rR|MAKEFLAGS += -g -rR|g' \
$OPENWRT_DIR/build_dir/target-aarch64_cortex-a72_musl/linux-bcm27xx_bcm2711/linux-5.15.132/Makefile
if grep -q "KBUILD_HOSTCFLAGS := " $OPENWRT_DIR/build_dir/target-aarch64_cortex-a72_musl/linux-bcm27xx_bcm2711/linux-5.15.132/Makefile; then
sed -i 's|KBUILD_HOSTCFLAGS := |KBUILD_HOSTCFLAGS := -g -O0 |g' \
$OPENWRT_DIR/build_dir/target-aarch64_cortex-a72_musl/linux-bcm27xx_bcm2711/linux-5.15.132/Makefile
fi
# And recompile
# And recompile. iptables-nft, gdbserver and recursive-test are already enabled
# (with their dependencies) in .config above, so just rebuild.
make -j4
########################################################################################################################
# Check build result
Expand All @@ -126,4 +154,4 @@ if [ $? -eq 0 ]; then
else
echo_red "Build failed."
exit 1
fi
fi
53 changes: 53 additions & 0 deletions tests/Rpi4/recursive_test_owrt/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
include $(TOPDIR)/rules.mk

PKG_NAME:=recursive-test
PKG_VERSION:=1.0
PKG_RELEASE:=1

PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)

include $(INCLUDE_DIR)/package.mk

# Keep the installed binary unstripped so it can be debugged on-target and so a
# host copy carries full symbols for Seer/GDB.
RSTRIP:=:

define Package/recursive-test
SECTION:=utils
CATEGORY:=Utilities
TITLE:=math_toolkit - recursion/struct test program for gdbserver + Seer
URL:=https://github.com/epasveer/seer
endef

define Package/recursive-test/description
A small C++ program (math_toolkit) with recursion, nested structs and a
long-running loop. Statically linked and non-PIE, built -g -O0, so remote
debugging on a Raspberry Pi 4 via gdbserver + Seer needs no shared-library
relocation and works identically in launch and --attach modes.
endef

define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/*.cpp $(PKG_BUILD_DIR)/
$(CP) ./include $(PKG_BUILD_DIR)/
endef

define Build/Compile
$(TARGET_CXX) \
-g -O0 -Wall -Wextra \
-static -no-pie -fno-pie \
-I$(PKG_BUILD_DIR)/include \
-o $(PKG_BUILD_DIR)/math_toolkit \
$(PKG_BUILD_DIR)/main.cpp \
$(PKG_BUILD_DIR)/arithmetic.cpp \
$(PKG_BUILD_DIR)/advanced.cpp \
-pthread \
-Wl,--start-group -lstdc++ -lgcc -lgcc_eh -Wl,--end-group
endef

define Package/recursive-test/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/math_toolkit $(1)/usr/bin/math_toolkit
endef

$(eval $(call BuildPackage,recursive-test))
34 changes: 34 additions & 0 deletions tests/Rpi4/recursive_test_owrt/include/advanced.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#ifndef ADVANCED_H
#define ADVANCED_H
#include <iostream>
#include <iostream>
#include <chrono>
#include <unistd.h>
#include <string>
#include <vector>

struct childStruct
{
int age;
std::string name;
};

struct parentStruct
{
int age;
std::string name;
childStruct childArr[100];
};

struct familyStruct
{
parentStruct dad;
int numberOfNumber;
char familyName[50];
parentStruct mom;
};

int factorial(int n);
int fibonacci(int n);

#endif
9 changes: 9 additions & 0 deletions tests/Rpi4/recursive_test_owrt/include/arithmetic.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#ifndef ARITHMETIC_H
#define ARITHMETIC_H

int add(int a, int b);
int subtract(int a, int b);
int multiply(int a, int b);
double divide(int a, int b);

#endif
Loading
Loading