需要在 GDB 中加载共享库的调试符号

Posted

技术标签:

【中文标题】需要在 GDB 中加载共享库的调试符号【英文标题】:Need to load debugging symbols for shared library in GDB 【发布时间】:2015-07-28 16:36:54 【问题描述】:

我正在使用 GDB 调试一个使用 libpthread 的程序。有错误 发生在 pthread_create 中,需要进入该函数。不幸的是,当我调试我的程序时,它没有正确加载共享库符号,所以我无法跨过源代码并有意义地检查程序行为。这是我启动 gdb 时的输出。

Remote debugging using 127.0.0.1:21293
warning: limiting remote suggested packet size (206696 bytes) to 16384
Failed to read a valid object file image from memory.

所以我相信最后一条消息与读取调试符号失败有关。尽管安装了 libc6-dbg 软件包,但仍然如此。这是在遇到 SIGSEGV 之前某个点的“where”的截断输出(在 pthread_create,我想在调试器中检查的函数)

#0  0x68200ce2 in ?? ()
#1  0x68403cbf in ?? ()
#2  0x687571b0 in ?? ()
#3  0x6874c638 in ?? ()
#4  0x68867a72 in ?? ()
....

进程的 /proc/.../maps 显示 libpthread 映射到内存的位置。

683f8000-68410000 r-xp 00000000 08:01 3017052                            /lib/i386-linux-gnu/i686/cmov/libpthread-2.19.so
68410000-68411000 r--p 00017000 08:01 3017052                            /lib/i386-linux-gnu/i686/cmov/libpthread-2.19.so
68411000-68412000 rw-p 00018000 08:01 3017052                            /lib/i386-linux-gnu/i686/cmov/libpthread-2.19.so

我相信如果我只能手动将调试符号加载到gdb中,那么我将能够跳过源代码并找到我的内存错误的根源。但是我不确定如何做到这一点。

我正在 x86_64 Debian 上调试一个 32 位程序。我应该怎么做才能将 libpthread 符号加载到 GDB 中以便有意义地调试它?

【问题讨论】:

为什么要调试libpthread? libpthread 极有可能是无可指责的。对我来说,您对pthread_create() 的论点似乎很明显有问题 - 您是在破坏pthread_attr_t 结构,还是为回调传递NULL,或者做任何其他微妙无效的事情? 假设将参数传递给pthread_create() 是个问题,从gdb 中抑制无意义的错误消息并没有什么坏处。 哦,错误出现在新线程,还是旧线程,segfault的时候是否已经创建了新线程? 我检查了非回调参数,它们似乎没有问题。我将调试跟踪放在回调中,但没有得到任何输出。我认为查看 pthread_create 中发生的情况以跟踪我的程序的无效行为是一个好主意。但是,我不认为 pthread_create 有问题。也许需要重新考虑? 您引用的错误 (Failed to read a valid object file image from memory.) 在所有 GDB 中仅发生一次,这是由于 GDB 未能在被调试进程的内存中找到 (ELF) 二进制对象的标头 -就好像您有一个不支持 32 位调试的 GDB(不太可能),或者可能是一种奇异的二进制格式。顺便问一下,当二进制文件在本地主机上时,我能问你为什么要远程调试吗? 【参考方案1】:

为共享库加载调试符号

如果共享库被剥离,并且调试符号作为单独的文件提供,则需要在链接器加载共享库之后加载它们。符号应该加载到加载共享库的内存地址上。

以下是加载符号的示例:

    启动 gdb

    ~$ gdb a.out
    GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2
    Copyright (C) 2020 Free Software Foundation, Inc.
    (gdb) info sharedlibrary
    No shared libraries loaded at this time.
    

    创建断点(在main 或任何其他地方)并开始调试

    (gdb) b 35
    Breakpoint 1 at 0xd7c: file test.c, line 35.
    (gdb) r
    Starting program: /root/testing/lib-test/a.out
    

    找到你要调试的共享库被加载的内存位置(在这个例子中库是libtest.so.1

    (gdb) info sharedlibrary
    From                To                  Syms Read   Shared Object Library
    0x0000fffff7fcd0c0  0x0000fffff7fe5468  Yes (*)     /lib/ld-linux-aarch64.so.1
    0x0000fffff7f9f890  0x0000fffff7fb65c0  Yes (*)     /usr/local/lib/libtest.so.1
    0x0000fffff7e4bbc0  0x0000fffff7f3b190  Yes         /lib/aarch64-linux-gnu/libc.so.6
    0x0000fffff7dfea50  0x0000fffff7e0ddec  Yes         /lib/aarch64-linux-gnu/libpthread.so.0
    

    所以,库从内存地址0x0000fffff7f9f890开始加载

    使用共享库中的地址加载符号文件

    (gdb) add-symbol-file ./libsrc/libtest.dbg 0x0000fffff7f9f890
    add symbol table from file "./libsrc/libtest.dbg" at
     .text_addr = 0xfffff7f9f890
    (y or n) y
    Reading symbols from ./libsrc/libtest.dbg...
    

之后,您可以跟踪库内部的执行流程、列出源代码的行、按名称检查变量等。

【讨论】:

以上是关于需要在 GDB 中加载共享库的调试符号的主要内容,如果未能解决你的问题,请参考以下文章

在 Python 中加载 C 共享库时出现 OSError(未定义符号:checkedCalloc)

在 Python ctypes 中加载共享库期间出现分段错误(核心转储)

没有共享系统库的精确调试符号的远程事后分析 coredump 分析

GDB 跳过共享库断点

gdb - 多线程和共享库

如何使用 GDB 调试共享对象库中的函数?