gdbserver是目标机上唯一需部署的调试组件,体积小、无图形界面、仅转发指令;必须匹配目标CPU架构编译,程序须带-g调试信息(保留.debug_*段),且确保端口通畅、库依赖完整、权限正确。

目标机必须运行 gdbserver
gdbserver 是目标机上唯一需要的调试组件,它不依赖完整 GDB,体积小、无图形界面、只负责转发调试指令。你不能在目标机上直接跑 gdb —— 那会占用大量资源,且多数嵌入式系统根本没装 libc 全集或符号表。
- 必须用与目标 CPU 架构匹配的
gdbserver:比如 ARMv7 板子不能用x86_64-linux-gnu-gdbserver,得是arm-linux-gnueabihf-gdbserver或海思平台专用的arm-himix200-linux-gdbserver - 编译时加
--host=arm-linux-gnueabihf(不是--target),否则生成的 gdbserver 无法在目标机上执行 - 若空间紧张,用
strip --strip-all gdbserver可减小 50% 以上体积,不影响功能
目标机程序必须带调试信息,但符号表可剥离
调试信息(.debug_* 段)必须保留在目标机二进制中,否则 gdbserver 无法解析变量名、行号;但符号表(.symtab、.strtab)可以删掉——它们只被 gdb 客户端使用,gdbserver 不需要。
- 编译时务必加
-g(推荐-g2,平衡信息量和体积) - 部署前可执行
strip --strip-unneeded ./myapp:保留调试段,删掉符号表,既节省空间又不影响远程调试 - 验证是否保留成功:
readelf -S ./myapp | grep debug应有若干.debug_*段;而nm ./myapp应基本为空(说明符号已剥离)
目标机网络或串口通道必须通,且端口未被占用
gdbserver 默认通过 TCP 监听,不走 SSH 或系统服务管理器。它一旦启动就独占端口,且不会自动重试绑定失败。
- 先确认端口空闲:
netstat -tuln | grep :2345(假设你要用 2345 端口) - 防火墙常被忽略:嵌入式 Linux 常用
iptables,执行iptables -L -n查看 INPUT 链是否放行该端口;临时关闭可用iptables -F - 用
nc -zv 192.168.1.100 2345从主机测连通性,比ping更准——ping通不代表端口可达 - 如果只能用串口(如无网口设备),要改用
gdbserver --once --remote-debug /dev/ttyS0,此时主机端需用target remote /dev/ttyUSB0
目标机文件系统要有可执行权限,且动态库能加载
gdbserver 本身是静态链接的,但你要调试的程序很可能依赖 libc、libpthread 等。如果提示 No such file or directory 或 cannot execute binary file,问题几乎都出在这里。
- 检查架构匹配:
file ./myapp输出应含ARM aarch64或ARM, EABI5等,和目标机uname -m一致 - 检查动态依赖:
./myapp直接运行报错?用ldd ./myapp看缺失哪些库;常见缺失是libstdc++.so.6或libgcc_s.so.1,需从交叉工具链的sysroot/lib同步过去 - 注意权限:
chmod +x ./gdbserver ./myapp,某些只读文件系统(如 squashfs)需挂载到可写分区再运行
远程调试真正卡住的地方,往往不是 gdb 命令输错,而是目标机上那个 gdbserver 进程根本没起来,或者起来了但连不上——因为端口被占、防火墙挡了、库缺了、甚至只是 ./gdbserver 权限不够。动手前花两分钟跑一遍上面四条检查项,比重启十次更省时间。


















