如果进程通过 dlopen() 手动加载动态库,某些情况下不能被 GDB 识别调试符号,这个时候可以通过 GDB 的 add-symbol-file file address 命令来手动添加调试符号,address 是动态库在进程中的 text 段 entry 地址,考虑动态库只有加载到进程中,才能得知真正的内存地址,因此我们可以通过 GDB 的 info files 命令,获取这个动态库在进程中的 text 段的 entry 地址。

下面是操作流程:

首先我们把目标动态库先反汇编,作为后续的比对验证对象:

objdump -d demo.so > demo.s

然后使用 gdb 调试目标进程,步骤如下:

 1(gdb) info files # 获取动态库 text 段 entry 地址
 2...
 30x00007f1fc9f3ba50 - 0x00007f1fca549490 is .text in /path/demo.so
 4...
 5(gdb) add-symbol-file /path/demo.so 0x00007f1fc9f3ba50 # 加载动态库调试信息(这里编译的动态库自带调试符号)
 6add symbol table from file "demo.so" at
 7                .text_addr = 0x7f1fc9f3ba50
 8(y or n) u
 9Reading symbols from demo.sp...done.
10(gdb) disassemble test_function # 查看任意动态库的函数,进行对比
11Dump of assembler code for funtion test_function:
120x...77adf0<+0>:     sub     $0x218.%rsp
130x...77adf7<+7>:     mov    %fs:0x28,%rax
14...

使用任意编辑器打开刚才反汇编好的 demo.s ,检索这个函数:

000000077adf0 <test_function>:
77adf0:   ...  sub     $0x218.%rsp
77adf7:   ...  mov    %fs:0x28,%rax

可以看到,GDB 反汇编的地址相对偏移以及指令,和 objdump 反汇编的结果都可以对上,再测试打断点,也可以停在正确位置上面。