我有一个崩溃进程的 gdb
回溯,但我看不到发生崩溃的具体行,因为源代码不在那个时刻。 我不理解上述回溯提供的一些信息。
回溯由如下几行组成:
<path_to_binary_file>(_Z12someFunction+0x18)[0x804a378]
请注意 _Z12someFunction
是 int someFunction(double )
的错位名称。
我的问题是:
+0x18
是否表示产生崩溃的汇编指令的偏移量,从 _Z12someFunction
地址开始?
如果前面的问题是肯定的,并且考虑到我正在使用 32 位架构,+0x18
是否表示 0x18 * 4 字节?
如果以上是肯定的,我假设地址0x804a378
是_Z12someFunction
加上0x18
,对吗?
编辑:
该错误发生在生产机器(未启用内核),而且似乎是时间相关的错误,因此不容易重现。那是因为在这种情况下,我所要求的信息对我来说很重要。
最佳答案
您的大部分假设都是正确的。 +0x18
确实意味着可执行文件的偏移量(以字节为单位,与体系结构无关)。
0x804a378
是实际发生错误的地址。
话虽如此,重要的是要了解您可以对此做些什么。
首先,使用-g
编译会产生调试符号。你,理所当然地,为你的生产构建剥离那些,但一切都没有丢失。如果您使用原始可执行文件(即 - 在对其进行 strip 化之前),您可以运行:
addr2line -e 可执行文件
然后您可以将 gdb 提供给您的地址 (0x804a378) 输入标准输入,addr2line 将为您提供该地址指向的精确文件和行。
如果你有一个核心文件,你也可以用未分割的可执行文件加载这个核心文件,并获得完整的调试信息。它仍然会有些损坏,因为您可能正在使用优化进行构建,但仍然应该可以访问一些变量。
使用调试符号构建并在发布前剥离是最佳选择。但是,即使您没有这样做,如果您在同一环境中使用相同的构建工具并使用相同的构建选项再次构建相同的源代码,您应该获得具有相同符号位置的相同二进制文件。如果错误真的很难重现,可能值得一试。
编辑添加
另外两个重要的工具是c++filt
。您向它提供一个损坏的符号,并生成实际源符号的 C++ 路径。它用作过滤器,因此您只需复制回溯并将其粘贴到 c++filt 中,它会为您提供相同的回溯,只是更具可读性。
第二个工具是gdb远程调试。这允许您在具有带调试符号的可执行文件的机器上运行 gdb,但在生产机器上运行实际代码。这允许在生产中进行实时调试(包括附加到已经运行的进程)。
关于c++ - 没有源代码时 gdb 回溯的含义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48462628/