使用gdb将地址转换为行号

45

我有一个被剥离的应用程序生成的堆栈跟踪,它看起来像这样:

 *** Check failure stack trace: ***
    @     0x7f0e442d392d  (unknown)
    @     0x7f0e442d7b1f  (unknown)
    @     0x7f0e442d7067  (unknown)
    @     0x7f0e442d801d  (unknown)
    @     0x7f0e457c55e6  (unknown)
    @     0x7f0e457c5696  (unknown)
    @           0x4e8765  (unknown)
    @           0x4a8b43  (unknown)
    @     0x7f0e43197ced  (unknown)
    @           0x4a6889  (unknown)

我有一个未剥离符号的可执行文件以及它的所有库(使用调试信息编译)。但是如何将地址转换为文件和行号呢?

这是我尝试过的方法:

gdb
set solib-absolute-prefix /path/to/non-stripped/edition/of/root/filesystem/sysroot/
file /path/to/non-stripped/edition/of/root/filesystem/sysroot/usr/bin/my-buggy-app
info line *0x7f0e457c5696

当我输入文件命令时,它只加载文件中使用的符号,而不是所有使用的库。有没有方法可以做到这一点?

"info line" 命令显示:

地址 0x7f0e442d801d 没有可用的行号信息

我想这是因为该地址在其中一个共享库中,但是如何知道是哪个库?


4
addr2line 是一个命令行工具,用于将程序的地址转换为源代码文件名和行号。它在调试崩溃或其他类似问题时非常有用。 - another.anon.coward
@another.anon.coward 我试过了,但我不知道要查找哪个文件,因为地址指向共享库。 - Allan
1
@Allan:您可以使用“info sharedlibrary”命令来查看地址“0x7f0e442d801d”属于哪个共享库。 - ks1322
我没有尝试过,但 add-symbol-file 文件名 地址 可能有助于从共享库(一次一个)加载符号。http://www.delorie.com/gnu/docs/gdb/gdb_125.html - thomasa88
发现一个库在sharedlibrary中没有符号,而且list 0xaddress没有显示任何源代码。我运行了add-symbol-file file addr,然后list 0xaddress就显示了源代码。 - thomasa88
2个回答

56

根据原帖,GDB中查找代码地址对应的源代码行的命令是:

info line *0x10045740

编辑:替换了在某些情况下无法正常工作的“信息符号0x10045740”(感谢@Thomasa88)。


4
这只显示符号和偏移量 (LftPlugin::import_clicked() const + 1522/home/thomas/.kde4/lib64/kde4/kmm_lft.so.text部分中),而 info line *0xabc则显示行号("plugin/lft_plugin.cpp"的第97行从地址0x7fffe49eb39c <LftPlugin::import_clicked() const+1522>开始,以0x7fffe49eb3ad <LftPlugin::import_clicked() const+1539> 结束)。在我的情况下,我的共享库没有被剥离,但当符号被剥离时,add-symbol-file filename address可能会有所帮助。http://www.delorie.com/gnu/docs/gdb/gdb_125.html - thomasa88
如何在MI模式下完成这个操作? - exebook

39

但我如何将地址翻译成文件和行号呢?

对于主可执行文件(像0x4e8765这样的地址),请执行以下操作:

addr2line -e /path/to/non-stripped/.../my-buggy-app \
    0x4a6889 0x4a8b43 0x4e8765

实际上,你可能需要从以上所有地址中减去5(通常是CALL指令的长度)。

对于共享库中的地址,你需要知道库的加载地址。

如果你的应用程序生成了一个core文件,则(gdb) info shared将告诉你库加载的位置。

如果你没有得到一个核心文件,并且应用程序也没有打印所需的映射信息,则:

  • 你应该修复应用程序,使其打印该信息(栈跟踪大多数情况下没有用),并且
  • 你仍然可以猜测:查看可执行文件中0x4e8760处的代码--它应该是调用某个函数的CALL指令。现在找出该函数位于哪个库中,并在库中找到它的地址(通过nm)。如果你运气好,那个地址就在0xNc56NN附近。现在你可以猜测0x7f0e457NNNNNN处是任何库的加载地址。重复操作,0x7f0e457c55e1,你可以找到0x7f0e442dNNNN处的库的加载地址。

我来到这里是因为addr2line不总是可靠的,而GDB非常稳定。 - exebook

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接