10

我们通过在客户的盒子上运行我们的软件来获取核心文件。不幸的是,因为我们总是在没有调试符号的情况下使用 -O2 进行编译,这导致我们无法弄清楚它为什么崩溃的情况,我们已经修改了构建,所以现在它们一起生成 -g 和 -O2。然后我们建议客户运行 -g 二进制文件,以便更容易调试。

我有几个问题:

  1. 当核心文件从我们在 Dev 中运行的 Linux 发行版以外的 Linux 发行版生成时会发生什么?堆栈跟踪是否有意义?
  2. 有没有关于在 Linux 或 Solaris 上进行调试的好书?面向示例的东西会很棒。我正在寻找现实生活中的示例,以找出例程崩溃的原因以及作者如何得出解决方案。中级到高级水平的东西会很好,因为我已经这样做了一段时间了。一些组装也会很好。

这是一个要求我们告诉客户获取 -g 版本的崩溃示例。二进制文件:

Program terminated with signal 11, Segmentation fault.
#0  0xffffe410 in __kernel_vsyscall ()
(gdb) where
#0  0xffffe410 in __kernel_vsyscall ()
#1  0x00454ff1 in select () from /lib/libc.so.6
...
<omitted frames>

理想情况下,我想找出应用程序崩溃的确切原因——我怀疑这是内存损坏,但我不是 100% 确定。

严禁远程调试。

谢谢

4

5 回答 5

29

当核心文件从我们在 Dev 中运行的 Linux 发行版以外的 Linux 发行版生成时会发生什么?堆栈跟踪是否有意义?

如果可执行文件是动态链接的,就像你的一样,GDB 产生的堆栈(很可能)没有意义。

原因:GDB 知道您的可执行文件通过libc.so.6在 address中调用某些内容而崩溃0x00454ff1,但它不知道该地址处的代码是什么。因此,它会查看您的副本libc.so.6并发现它在 中select,因此它会打印它。

但是,在您的客户副本中0x00454ff1也被选中的机会非常小。客户很可能在那个地址有一些其他的程序,也许。libc.so.6abort

您可以使用disas select, 并观察它0x00454ff1在指令中间,或者前面的指令不是CALL. 如果其中任何一个成立,您的堆栈跟踪就毫无意义。

但是,您可以自助:您只需(gdb) info shared要从客户系统中获取列出的所有库的副本。让客户使用例如焦油

cd /
tar cvzf to-you.tar.gz lib/libc.so.6 lib/ld-linux.so.2 ...

然后,在您的系统上:

mkdir /tmp/from-customer
tar xzf to-you.tar.gz -C /tmp/from-customer
gdb /path/to/binary
(gdb) set solib-absolute-prefix /tmp/from-customer
(gdb) core core  # Note: very important to set solib-... before loading core
(gdb) where      # Get meaningful stack trace!

然后我们建议客户运行 -g 二进制文件,以便更容易调试。

一个更好的方法是:

  • 建立与-g -O2 -o myexe.dbg
  • strip -g myexe.dbg -o myexe
  • myexe发给客户
  • 当客户得到一个coremyexe.dbg用来调试它

您将获得完整的符号信息(文件/行、局部变量),而无需向客户发送特殊的二进制文件,也无需透露有关您的来源的太多细节。

于 2012-05-17T03:28:21.667 回答
2

您确实可以从故障转储中获得有用的信息,甚至是从优化编译中获得的信息(尽管从技术上讲,这就是所谓的“屁股的主要痛苦”。)-g编译确实更好,是的,您甚至可以这样做当发生转储的机器是另一个发行版时。基本上,需要注意的是,所有重要信息都包含在可执行文件中,并最终出现在转储中。

当您将核心文件与可执行文件匹配时,调试器将能够告诉您崩溃发生的位置并显示堆栈。这本身应该有很大帮助。您还应该尽可能多地了解它发生的情况——他们能可靠地重现它吗?如果是这样,你能重现它吗?

现在,这里有一个警告:“一切都在那里”的概念被打破的地方是共享对象文件,.so文件。如果由于这些问题而失败,您将没有所需的符号表;您可能只能看到.so它发生在哪个库中。

有很多关于调试的书籍,但我想不出我会推荐的一本。

于 2012-05-16T10:22:34.680 回答
0

据我记得,您不需要要求您的客户使用使用 -g 选项构建的二进制文件运行。需要的是你应该有一个带有 -g 选项的构建。有了它,您可以加载核心文件,它将显示整个堆栈跟踪。我记得几周前,我创建了核心文件,带有 build (-g) 和没有 -g,核心的大小是相同的。

于 2012-05-16T10:16:53.837 回答
0

检查您在堆栈中看到的局部变量的值?特别是在 select() 调用周围。在客户的盒子上执行此操作,只需加载转储并遍历堆栈...

此外,检查您的 DEV 和 PROD 平台上的 FD_SETSIZE 的值!

于 2012-05-16T13:47:04.103 回答
0

我的问题中复制解决方案,该问题被认为与此问题重复。

set solib-absolute-prefix接受的解决方案对我没有帮助。set sysroot使 gdb 加载本地提供的库是绝对必要的。这是我用来打开核心转储的命令列表:

# note: all the .so files obtained from user machine must be put into local directory.
#
# most importantly, the following files are necessary:
#   1. libthread_db.so.1 and libpthread.so.0: required for thread debugging.
#   2. other .so files are required if they occur in call stack.
#
# these files must also be renamed exactly as the symlinks
# i.e. libpthread-2.28.so should be renamed to libpthread.so.0

# load executable file
file ./thedarkmod.x64

# force gdb to forget about local system!
# load all .so files using local directory as root
set sysroot .

# drop dump-recorded paths to .so files
# i.e. load ./libpthread.so.0 instead of ./lib/x86_64-linux-gnu/libpthread.so.0
set solib-search-path .
# disable damn security protection
set auto-load safe-path /

# load core dump file
core core.6487

# print stacktrace
bt
于 2021-09-22T04:39:45.207 回答