唯一稳定通用做法是gdbserver在目标设备启动程序、交叉gdb客户端远程连接;需确保程序带-g编译、gdbserver可执行、依赖库齐全,且用continue而非run恢复执行。

直接用 gdbserver 在目标设备上启动程序,再用交叉编译的 gdb 客户端连过去——这是唯一稳定、通用的做法。其他“免配置”方案(比如直接在板子上跑 gdb)基本不可行,因为嵌入式设备内存和存储都不够。
目标设备上运行 gdbserver 的关键参数
必须确保三点:程序带 -g 编译、gdbserver 可执行、依赖库齐全。
-
gdbserver启动命令格式固定:gdbserver <host>:<port><program> [args...]</program></port></host>,例如:gdbserver 192.168.1.100:2345 ./myapp --verbose - 如果报错
error while loading shared libraries: libthread_db.so.1,说明缺少libthread_db,要从交叉工具链的sysroot/lib下拷贝libthread_db.so.1和libthread_db-1.0.so到目标设备的/lib或/usr/lib - 目标设备 IP 必须能被宿主机 ping 通,且端口未被防火墙拦截(常见问题:开发板默认关掉
iptables,但某些定制 rootfs 会开)
宿主机用交叉 gdb 连接时的常见陷阱
不是所有叫 gdb 的二进制都能连上 gdbserver;必须是和目标架构匹配、且编译时启用了 remote 支持的版本。
- 确认你用的是交叉
gdb,比如aarch64-linux-gnu-gdb或arm-linux-gnueabihf-gdb,而不是系统自带的gdb - 连接前必须先加载符号文件:
aarch64-linux-gnu-gdb ./myapp,再在(gdb)提示符下输入:target remote 192.168.1.100:2345 - 如果遇到
Remote 'g' packet reply is too long错误(尤其在 Hi3556v200、RK3399 等平台),说明gdb内置寄存器描述和目标 CPU 不匹配,需重新编译gdb并 patchremote.c中的sizeof_g_packet检查逻辑 - 调试时看不到变量名或源码行号?检查编译命令是否漏了
-g,以及gdb加载的是否为同一份二进制(注意:./myapp是宿主机上的调试文件,不是目标设备上运行的那个)
调试过程中 continue 代替 run 的原因
因为程序已经在目标设备上由 gdbserver 启动并暂停了,gdb 客户端只是接管控制权。所以不能用 run(它会尝试在本地 fork+exec),而必须用 continue(或简写 c)恢复远程进程执行。
- 断点设置后首次执行必须用
c,否则会提示The program is not being run - 如果程序启动即崩溃(比如段错误),可在连接后立刻用
handle SIGSEGV stop print捕获信号,再c触发,这样能停在出错第一现场 -
bt(backtrace)看到的调用栈深度受限于目标设备是否启用了帧指针(-fno-omit-frame-pointer)。ARM64 默认不生成 fp,加这个编译选项能让bt更准
真正容易被忽略的是:每次修改代码重编译后,必须手动 kill 掉目标设备上旧的 gdbserver 进程,否则新程序无法覆盖部署(Text file busy)。自动化脚本里一定要包含 ssh user@target 'pkill -f "gdbserver.*myapp"' 这一步,不然你会反复卡在“为什么改了代码没生效”。











