GDB attach 时加载带调试信息的共享库符号
问题
进程运行时链接的是 stripped 的共享库(无调试信息),attach 后无法查看库函数的源码和断点信息。需要让 GDB 使用另一份带调试信息的 so 来加载符号。
以 libzmq 为例:进程加载的是 /lib/aarch64-linux-gnu/libzmq.so.5(无调试信息),而 /home/data/libzmq/ 下有编译时保留调试信息的版本。
关键认知
GDB attach 不能改变进程的库加载路径。 进程启动时 execve 和动态链接器已完成路径解析,/proc/<pid>/maps 中的映射不可更改。GDB 能做的只是替换符号文件的查找来源。
方案对比
| 方案 | 原理 | 优缺点 |
|---|---|---|
set solib-search-path | 按文件名在指定目录搜索符号文件 | 仅在原始路径文件不存在时回退搜索,本地文件存在时无效 |
set sysroot | 路径前缀重定向 | 需要构造完整目录结构,影响所有库的查找 |
add-symbol-file | 手动指定符号文件和加载地址 | 最直接,不影响其他库,推荐 |
| 临时替换原文件 | 替换系统目录下的 so | 暴力有效,但影响全局,需恢复 |
推荐方案:add-symbol-file
步骤
- 查看目标库的加载地址
gdb
(gdb) info sharedlibrary libzmq
From To Syms Read Shared Object Library
0x0000ffffa18124e0 0x0000ffffa186f344 Yes (*) /lib/aarch64-linux-gnu/libzmq.so.5 起始地址 0x0000ffffa18124e0 即 .text 段地址。
- 加载带调试信息的符号文件
gdb
(gdb) add-symbol-file /home/data/libzmq/libzmq.so.5 0x0000ffffa18124e0
add symbol table from file "/home/data/libzmq/libzmq.so.5" at
.text_addr = 0xffffa18124e0
(y or n) y
Reading symbols from /home/data/libzmq/libzmq.so.5... - 验证符号加载成功
gdb
(gdb) info functions zmq_send
All functions matching regular expression "zmq_send":
File /home/user/workspace/libzmq/src/zmq.cpp:
356: int zmq_send(void*, void const*, size_t, int);
383: int zmq_send_const(void*, void const*, size_t, int);
415: int zmq_sendiov(void*, iovec*, size_t, int);
351: int zmq_sendmsg(void*, zmq_msg_t*, int); 能列出源码位置和函数签名,说明符号生效。
- 正常调试
gdb
(gdb) b zmq_send
(gdb) b zmq.cpp:356
(gdb) list zmq_send 注意事项
info sharedlibrary中该库仍显示Yes (*),这是正常的——它反映的是进程原始加载的 so 的状态,不影响add-symbol-file附加的符号- 如果
info functions找不到函数,说明指定的 so 本身也是 stripped 的,需要确认文件是否包含调试信息:
bash
readelf -S /home/data/libzmq/libzmq.so.5 | grep debug solib-search-path 为什么无效
set solib-search-path 的工作机制:
- GDB 取进程已加载库的文件名(如
libzmq.so.5) - 先尝试原始绝对路径
/lib/aarch64-linux-gnu/libzmq.so.5 - 只有原始路径文件不存在时,才回退到
solib-search-path指定的目录搜索
由于 /lib/aarch64-linux-gnu/libzmq.so.5 在本地存在,GDB 直接使用了它,solib-search-path 被跳过。
sysroot 方案(备选)
当需要批量替换多个库的符号时,构造 sysroot 目录结构更高效:
bash
# 构造与原始路径一致的目录结构
mkdir -p /home/data/sysroot/lib/aarch64-linux-gnu/
cp /home/data/libzmq/libzmq.so.5.2.2 /home/data/sysroot/lib/aarch64-linux-gnu/
cd /home/data/sysroot/lib/aarch64-linux-gnu/
ln -sf libzmq.so.5.2.2 libzmq.so.5
ln -sf libzmq.so.5 libzmq.so gdb
(gdb) set sysroot /home/data/sysroot
(gdb) set solib-search-path /lib/aarch64-linux-gnu:/home/efort/lib solib-search-path 作为补充,让 GDB 能找到 sysroot 中未覆盖的其他库。
精确获取 .text 段地址
info sharedlibrary 显示的起始地址通常就是 .text 段地址。如需精确确认:
bash
cat /proc/<pid>/maps | grep libzmq 输出中 r-xp(可读可执行)权限的行即为 .text 段:
ffffa18124e0-ffffa186f344 r-xp 00000000 ... /lib/aarch64-linux-gnu/libzmq.so.5 总结
- attach 后无法改变进程的库加载路径,只能替换 GDB 的符号查找来源
add-symbol-file是最干净的方案:一行命令,不影响其他库,不需要修改任何文件info sharedlibrary的(*)标记不影响实际调试,以info functions和断点设置验证为准solib-search-path在原始路径文件存在时不会生效,这是最常见的踩坑点