【问题标题】:Meaning of a gdb backtrace when there is not source code没有源代码时 gdb 回溯的含义
【发布时间】:2018-07-05 20:50:11
【问题描述】:

我有一个崩溃进程的gdb 回溯,但我看不到发生崩溃的具体行,因为源代码不在那个时刻。 我不明白提到的回溯给出的一些信息。

回溯由如下几行组成:

<path_to_binary_file>(_Z12someFunction+0x18)[0x804a378]

注意_Z12someFunctionint someFunction(double ) 的错名。

我的问题是:

+0x18 是否表示从_Z12someFunction 地址开始的产生崩溃的汇编指令的偏移量?

如果前面的问题是肯定的,并且考虑到我正在使用 32 位架构,+0x18 是否表示 0x18 * 4 字节?

如果以上是肯定的,我假设地址0x804a378_Z12someFunction加上0x18,对吗?

编辑:

错误发生在生产机器(未启用内核)中,并且似乎是与时间相关的错误,因此不容易重现。那是因为我所要求的信息在这个场合对我很重要。

【问题讨论】:

  • 只需构建带有调试信息的二进制文件
  • 除了偏移量是字节而不是 32 位字之外,你什么都对。
  • 我们能看到你的编译命令吗?我怀疑你是用太低的调试模式构建的。
  • 是的,编译是经过优化且没有调试符号的,但我无法仅使用调试信息进行编译来解决我的问题,因为我无法轻松重现错误。
  • 但这不是gdb回溯,它是glibc backtrace

标签: c++ debugging gdb reverse-engineering disassembly


【解决方案1】:

您的大多数假设都是正确的。 +0x18 确实表示可执行文件的偏移量(以字节为单位,与架构无关)。

0x804a378 是发生错误的实际地址。

话虽如此,重要的是要了解您可以做些什么。

首先,使用-g 编译会产生调试符号。您理所当然地为您的生产构建剥离了这些,但一切都没有丢失。如果您使用原始可执行文件(即 - 在您对其进行条带化之前),您可以运行: addr2line -e executable

然后,您可以将 gdb 提供给您的地址 (0x804a378) 输入标准输入,addr2line 将为您提供该地址所引用的精确文件和行。

如果你有一个核心文件,你也可以用非条带化的可执行文件加载这个核心文件,并获得完整的调试信息。它仍然会有些混乱,因为您可能正在使用优化进行构建,但一些变量应该仍然可以访问。

使用调试符号构建并在发货前进行剥离是最佳选择。但是,即使您没有这样做,但如果您在相同的环境中使用相同的构建工具并使用相同的构建选项再次构建相同的源代码,您应该获得具有相同符号位置的相同二进制文件。如果该错误确实难以重现,则可能值得一试。

编辑添加

另外两个重要的工具是c++filt。你给它一个错位符号,并生成到实际源符号的 C++ 路径。它用作过滤器,因此您只需复制回溯并将其粘贴到 c++filt 中,它就会为您提供相同的回溯,只是更具可读性。

第二个工具是gdb远程调试。这允许您在具有带有调试符号的可执行文件的机器上运行 gdb,但在生产机器上运行实际代码。这允许在生产中进行实时调试(包括附加到已经运行的进程)。

【讨论】:

  • 我尝试使用addr2line,但既找不到我拥有的地址,也找不到函数地址(我用nm -D提取的)。我的意思是,addr2line 显示:??:0。我试图将函数地址减 5,因为我读到那是 CALL 指令的长度。
  • 在某些情况下,GDB 可以检测到行号,但 addr2line 不能。我一直无法弄清楚是什么原因造成的。
  • 当然,我假设您确保在使用 addr2line 加载的可执行文件中有调试符号。您可以尝试在 GDB 中加载此可执行文件,启动程序,然后手动将您的 EIP 设置为该地址,然后查看 gdb 显示您所在的位置。如果这不起作用,那你就不走运了。
  • 我已经用 gdb 完成了,事实上,我已经能够通过 info synbol &lt;addr&gt; 看到函数名称。它在.text 部分,我尝试使用addr2line 指定-j .text,但我得到了相同的结果。
【解决方案2】:

你很困惑。您看到的是 glibc's backtrace 函数的回溯输出,而不是 gdb 的回溯。

但我看不到发生崩溃的具体行,因为 源代码不在那个时候

现在您可以在 gdb 中加载可执行文件并检查地址 0x804a378 以获取行号。您可以使用list *0x804a378info symbol 0x804a378。请参阅Convert a libc backtrace to a source line numberHow to use addr2line command in linux

【讨论】:

    【解决方案3】:

    运行 man gcc,您应该会看到 -g 选项,它使您可以将调试信息添加到二进制对象文件中,因此当崩溃发生并且核心被转储时,gdb 可以检测崩溃发生的确切位置和原因,或者您可以使用 gdb 运行该进程或附加到它并直接查看跟踪,而无需搜索核心文件。

    【讨论】:

    • 当然可以,但是错误已经发生过一次,在没有启用转储的远程机器上,并且无法轻松重现(似乎是与时间相关的错误)。
    • 在这种情况下,我建议要么找到简单的方法来复制或高于 Shachar 的答案,我相信根据您提供的内容涵盖了所有内容。
    猜你喜欢
    • 2017-12-07
    • 2014-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多