Skip to content
Blogster on GitHub Dinesh on Twitter

gdb调试如何进入glibc

在使用gdb进行debug时,有时候我们需要调试glibc(libc),例如pthread_create, fgets等等,即使我们的二进制在编译阶段已经加了-g选项,但是我们单步进入的时候会遇到No such file or directory的错误,这是因为我们使用的glibc库函数存在于动态链接的libc.so.6中,但我们二进制所链接的glibc是不存在 调试信息(debug info) 的. 接下来笔者会一步一步介绍如何生成带debug info的glibc,并通过gdb配置使glibc变得可调试。

Debug info

我们可以通过readelf -S /path/to/shared_library | grep debug 来查看某个库是否包含debug info。
这里以笔者机器上的glibc为例,首先查看glibc库的路径: sudo ldconfig -p | grep libc.so.6

$ sudo ldconfig -p | grep libc.so.6
	libc.so.6 (libc6,x86-64) => /lib/x86_64-linux-gnu/libc.so.6
	libc.so.6 (libc6) => /lib32/libc.so.6

查看glibc库是否包含debug info:

$ readelf -S /lib/x86_64-linux-gnu/libc.so.6 | grep debug
  [62] .gnu_debuglink    PROGBITS         0000000000000000  001d3ff4

包含以上及其类似结果表示glibc不包含debug info,包含debug info的glibc库的结果如下, section名前缀会包含.debug。

  [67] .debug_aranges    PROGBITS         0000000000000000  001b5180
  [68] .debug_info       PROGBITS         0000000000000000  001c8760
  [69] .debug_abbrev     PROGBITS         0000000000000000  00b8015b
  [70] .debug_line       PROGBITS         0000000000000000  00c8cd3f
  [71] .debug_str        PROGBITS         0000000000000000  00e700d8
  [72] .debug_loc        PROGBITS         0000000000000000  00e9c233
  [73] .debug_ranges     PROGBITS         0000000000000000  01138457

源码编译带debug info的glibc

笔者以glibc 2.36版本(笔者机器上glibc的版本)源码为例子, 从glibc官方下载地址下载glibc源码并解压

$ wget https://ftp.gnu.org/gnu/glibc/glibc-2.36.tar.gz && tar -xzf glibc-2.36.tar.gz
$ cd glibc-2.36.tar.gz

创建单独的目录用于构建,并配置编译选项。

$ mkdir build && cd build
$ ../configure --prefix=/usr/share/glibc-2.36

必须创建单独的build目录用于构建,否则会出现如下错误

configure: error: you must configure in a separate build directory

其中configure的详细参数配置可以参考glibc configure,默认不加编译参数CFLAGS的话,glibc会指定为-g -O2,也就是说默认会生成带有debug info的glibc,--prefix参数指定了glibc会被安装到哪个路径,这里只能是绝对路径才有效。

源码编译glibc, 等待编译结束

$ make -j`nproc`

在编译完成后,我们会看到当前目录, 也就是build目录下,已经生成了glibc动态链接库,查看一下已经带有debug info.

$ readelf -S libc.so | grep debug
  [61] .debug_aranges    PROGBITS         0000000000000000  001c8020
  [62] .debug_info       PROGBITS         0000000000000000  001e0370
  [63] .debug_abbrev     PROGBITS         0000000000000000  00760738
  [64] .debug_line       PROGBITS         0000000000000000  0084da65
  [65] .debug_str        PROGBITS         0000000000000000  0098dc2f
  [66] .debug_line_str   PROGBITS         0000000000000000  009bc7a5
  [67] .debug_loclists   PROGBITS         0000000000000000  009c8035
  [68] .debug_rnglists   PROGBITS         0000000000000000  00b28ceb

安装glibc

$ sudo make install

命令执行结束后,glibc会被安装/usr/share/glibc-2.36下, 动态链接库会位于/usr/share/glibc-2.36/lib目录下

调试glibc

gdbinit配置

我们只需要在.gdbinit中设置set env LD_LIBRARY_PATH=/path/to/shared_library就可以调试glibc了。

$ echo "set env LD_LIBRARY_PATH=/usr/share/glibc-2.36/lib" >> ~/.gdbinit

debugging inside glibc

我们以hello world为例子进行调试,hello world代码如下:

#include <stdio.h>

int main() {
    printf("Hello world!\n");
    return 0;
}

编译 && 调试

$ gcc main.c -g && gdb ./a.out

我们在printf处单步进入,已经可以跳转到相关的代码了

References

https://www.gnu.org/software/hurd/faq/debugging_inside_glibc.html https://www.gnu.org/software/libc/manual/html_node/Configuring-and-compiling.html