OpenBMC 应用远程调试
由于 qemu 模拟的 romulus 机器性能太差,且内存最大只能设置 1G,如果直接进行本地调试基本上 gdb 进程直接就 oom 被杀掉了。

以 bmcweb 为例,演示通过 qemu 进行 OpenBMC 应用的远程调试。

基础信息

bmcweb 基于 OpenBMC 最新的代码(v2.14+)进行构建;
基础运行环境基于 OpenBMC v2.8 进行构建,并启用了 NFS 支持(否则根本不可能有空间存储带调试符号的可执行文件和动态库);
flash 大小为 128M(默认的 32M 空间有点小,改成 128M 更方便,当然需要内核 dtb 以及 qemu 命令行等一系列的修改);

qemu 命令行如下:

❯ qemu-system-arm -m 1g -M romulus-bmc,fmc-model=mx66l1g45g -nographic -drive file=obmc-phosphor-image-romulus-20231227020028.static.mtd,format=raw,if=mtd -net nic -net user,hostfwd=::2222-:22,hostfwd=::2443-:443,hostfwd=udp::2623-:623,hostfwd=::1234-:1234,hostname=qemu

image w/ gdbserver

为 bmc 镜像增加 gdbserver 等调试工具:

❯ vi build/romulus/conf/local.conf
EXTRA_IMAGE_FEATURES ?= "debug-tweaks tools-debug"

app w/ debug info

需要准备的内容包括 bmcweb 自身以及它所依赖的 gcc-runtime, glibc, libgcc, boost 等动态库:

❯ tree
.
├── bmcweb
├── boost
│   ├── libboost_chrono.so.1.83.0
│   ├── libboost_context.so.1.83.0
│   ├── libboost_coroutine.so.1.83.0
│   ├── libboost_thread.so.1.83.0
│   └── libboost_url.so.1.83.0
├── gcc-runtime
│   ├── libatomic.so.1.2.0
│   ├── libgomp.so.1.0.0
│   ├── libitm.so.1.0.0
│   ├── libstdc++.so.6 -> libstdc++.so.6.0.32
│   └── libstdc++.so.6.0.32
├── glibc
│   ├── ld-linux.so.3
│   ├── libanl.so.1
│   ├── libBrokenLocale.so.1
│   ├── libc_malloc_debug.so.0
│   ├── libc.so.6
│   ├── libdl.so.2
│   ├── libmemusage.so
│   ├── libm.so.6
│   ├── libnsl.so.1
│   ├── libnss_compat.so.2
│   ├── libnss_db.so.2
│   ├── libnss_dns.so.2
│   ├── libnss_files.so.2
│   ├── libnss_hesiod.so.2
│   ├── libpcprofile.so
│   ├── libpthread.so.0
│   ├── libresolv.so.2
│   ├── librt.so.1
│   ├── libthread_db.so.1
│   └── libutil.so.1
└── libgcc
    └── libgcc_s.so.1

注意拷贝 image 目录下的可执行文件和动态库,以 bcmweb 为例说明如下:

  • image/usr/bin/bmcweb 是原始构建出来的带调试符号的 bmcweb 可执行文件;
  • package/usr/bin/bmcweb 是 strip 了调试符号的 bmcweb 可执行文件;
  • package/usr/bin/.debug/bmcweb 是 bmcweb 可执行文件的调试符号;
  • packages-split/bmcweb/usr/bin/bmcweb 待打包的 strip 了调试符号的 bmcweb 可执行文件;
  • packages-split/bmcweb-dbg/usr/bin/.debug/bmcweb 待打包的 bmcweb 可执行文件的调试符号;

是不是和 rpm 的构建似曾相识,以前的 OpenBMC 默认就是用的 rpm 格式打包,新版本才切成 ipk 格式。

修改 bmcweb 动态链接库的搜索路径:

❯ patchelf --set-interpreter ./glibc/ld-linux.so.3 --set-rpath '$ORIGIN:$ORIGIN/glibc:$ORIGIN/gcc-runtime:$ORIGIN/boost:$ORIGIN/libgcc' --force-rpath ./bmcweb

所有可执行文件和动态库拷贝到 NFS 共享上,OpenBMC 虚机通过 NFS 访问这些文件。

gdb remote debug

gdb server

挂载 NFS 共享:

root@romulus:~# mount -t nfs -o nfsvers=2 10.0.1.105:/home/runsisi/bmc /media/

通过 gdbserver 启动 bmcweb:

root@romulus:/media/bmcapp# gdbserver :1234 ./bmcweb 
Process ./bmcweb created; pid = 748
Listening on port 1234

clion client

其中 Sysroot 通过如下脚本生成:

https://github.com/runsisi/obmc-utils/blob/master/obmc-sysroot.py

❯ python obmc-sysroot.py -b ~/working/bmc/openbmc/build/romulus -r ~/working/test/bmcroot

*** setup bmc sysroot succeeded! ***

export PATH=\
/home/runsisi/working/test/bmcroot/sysroot-native/usr/bin/arm-openbmc-linux-gnueabi:\
/home/runsisi/working/test/bmcroot/sysroot/usr/bin/crossscripts:\
/home/runsisi/working/test/bmcroot/sysroot-native/usr/sbin:\
/home/runsisi/working/test/bmcroot/sysroot-native/usr/bin:\
/home/runsisi/working/test/bmcroot/sysroot-native/sbin:\
/home/runsisi/working/test/bmcroot/sysroot-native/bin\
$PATH

GCC --sysroot=/home/runsisi/working/test/bmcroot/sysroot, e.g.,
arm-openbmc-linux-gnueabi-gcc --sysroot=/home/runsisi/working/test/bmcroot/sysroot -o x x.c
arm-openbmc-linux-gnueabi-gdb ./x

gdb client

设置通过 obmc-sysroot.py 生成的 PATH 环境变量,然后启动 arm-openbmc-linux-gnueabi-gdb 即可(相比 clion 主要是需要手工设置 substitute-path 会稍微麻烦一点点,同时 OpenBMC 默认构建的 gdb 没有 tui 之类的辅助,因此会更麻烦):

❯ arm-openbmc-linux-gnueabi-gdb
GNU gdb (GDB) 13.2
(gdb) file bmcweb 
Reading symbols from bmcweb...
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
Reading symbols from ./glibc/ld-linux.so.3...
0x76feea90 in _start () from ./glibc/ld-linux.so.3
(gdb) b main
Breakpoint 1 at 0x43e1d4: file /usr/src/debug/bmcweb/1.0+git/src/webserver_main.cpp, line 157.
(gdb) set substitute-path /usr/src/debug/bmcweb/1.0+git /home/runsisi/working/bmc/openbmc/build/romulus/workspace/sources/bmcweb
(gdb) set substitute-path /usr/include/c++/13.2.0 /home/runsisi/working/test/bmcroot/sysroot/usr/include/c++/13.2.0
(gdb) c

当然,也可以直接安装 gdb-multiarch,这样会比直接使用 OpenBMC 默认构建的 gdb 更简单:

❯ sudo pacman -S gdb-multiarch
❯ gdb-multiarch
GNU gdb (GDB) 13.2
(gdb) file bmcweb
Reading symbols from bmcweb...
(gdb) set substitute-path /usr/src/debug/bmcweb/1.0+git /home/runsisi/working/bmc/openbmc/build/romulus/workspace/sources/bmcweb
(gdb) set sysroot /home/runsisi/working/test/bmcroot/sysroot
(gdb) b main
Breakpoint 1 at 0x3e1d4: file /usr/src/debug/bmcweb/1.0+git/src/webserver_main.cpp, line 157.
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
Reading symbols from ./glibc/ld-linux.so.3...
0x76feea90 in _start () from ./glibc/ld-linux.so.3
(gdb) info b
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   0x0043e1d4 in main(int, char**) 
                                           at /usr/src/debug/bmcweb/1.0+git/src/webserver_main.cpp:157

appendix

Debugging Tools and Techniques
https://docs.yoctoproject.org/dev-manual/debugging.html


最后修改于 2024-01-03