远程调试必须加 -g 且禁用优化(-o0),确保 libc 含 dwarf 调试信息、gdbserver 启动带 --once 参数,否则断点失效、单步错乱或连接失败。

编译时必须加 -g 且禁用优化
远程调试依赖完整的调试信息,LLVM 默认不生成 DWARF(-g 关闭),且优化会破坏变量生命周期、内联函数、重排控制流,导致 GDB/LLDB 步进错乱或断点失效。
-
-g是硬性要求,不能只写-ggdb或-g3—— LLVM 的clang对调试信息等级不敏感,-g就够了 - 必须显式禁用优化:
-O0,哪怕只加-O1都可能让局部变量在寄存器中“消失”,GDB 显示<optimized out></optimized> - 避免
-fomit-frame-pointer(Clang 默认在-O2及以上启用),否则栈回溯失败;-O0下默认关闭,不用额外关 - 如果目标平台是 ARM,别漏掉浮点 ABI 一致性:调试器依赖符号和调用约定,
-mfloat-abi=hard必须和 sysroot 中 libc 编译时一致,否则单步进入 printf 等函数会跳飞
--sysroot 路径里得有调试友好的 libc
标准交叉 sysroot(如 Buildroot 输出)通常不含调试符号。GDB 远程调试时,若 libc 函数内无法单步或显示源码,大概率是因为 libc.so 没带 DWARF 或 /usr/lib/debug 缺失。
- 优先用 Buildroot 的
BR2_ENABLE_DEBUG选项构建 sysroot,它会自动把调试符号分离到target-debug子目录 - 手动补符号:若已有 sysroot,可从对应发行版(如 Debian armhf)下载
libc6-dbg包,解压后把usr/lib/debug/lib/arm-linux-gnueabihf/libc-*.so复制到 sysroot 的usr/lib/debug/lib/下 - 验证方式:在目标板上运行
readelf -w /lib/arm-linux-gnueabihf/libc.so.6 | head -n5,有输出即含调试信息;空则无 - 注意路径映射:GDB 默认按本地路径找源码,若 sysroot 是
/opt/sysroot-armhf,需在 GDB 中执行set sysroot /opt/sysroot-armhf,否则找不到stdio.h对应的调试行号
链接阶段要保留调试节且不 strip
Clang 默认链接时不 strip,但若用了 -Wl,--strip-all 或构建脚本里调了 arm-linux-gnueabihf-strip,调试信息就全丢了——不是“看不到”,是根本不存在。
- 检查最终二进制:运行
file hello-arm,输出含with debug_info才正常;若写stripped,说明被清掉了 - 确认链接命令没含
--strip-all、--strip-unneeded或-s;CMake 用户尤其注意CMAKE_EXE_LINKER_FLAGS是否误加了这些 - 如果必须减小体积(比如 Flash 限制),改用
-Wl,--only-keep-debug把调试信息抽成 .debug 文件,再用objcopy --strip-debug去主程序,但调试时得让 GDB 加载那个 .debug 文件(麻烦且易出错,不推荐) - ARM 上常见陷阱:链接器脚本(
.ld)里写了/DISCARD/ { *(.comment) *(.note*) },可能误删.debug_*节——检查是否漏加了*(.debug_*)保护
GDBserver 启动参数影响调试稳定性
远程调试不是编译完就能连,GDBserver 在目标板上的行为直接决定能否 attach、能否捕获信号、是否支持多线程断点。
- 务必加
--once参数:gdbserver :2345 ./hello-arm会持续监听,但崩溃后进程退出,GDB 断连;gdbserver --once :2345 ./hello-arm运行完自动退出,适合单次调试 - 若程序 fork 多进程,必须加
--wrapper /bin/sh -c或用set follow-fork-mode child,否则 GDBserver 默认只跟踪父进程 - ARM 板资源紧张时,GDBserver 可能因内存不足崩溃,此时加
-v查日志,常见报错Cannot access memory at address 0x...往往是 stack overflow 或 MMU 配置问题,不是编译问题 - 别用
gdb-multiarch直连 ARM 板 IP:它不处理目标端架构差异,必须用原生arm-linux-gnueabihf-gdb或aarch64-linux-gnu-gdb(取决于 target),否则寄存器视图错乱、PC 偏移异常
--once 导致反复重连失败——这两点不解决,前面所有 -g 都白加。











