10

我的程序是用dietlibc 静态编译的。它在 ubuntu x64 上编译(使用 -m32 标志为 x86 编译)并在 centos x86 上运行。

编译后的大小只有100KB左右。我用 -ggdb3 编译它,没有优化标志。

我的程序使用 signal.h 处理 SIGSEGV 信号,然后调用 abort()。

该程序运行几天没有问题,但有时会出现段错误。这是当我得到我不理解的奇怪回溯时:

用户名@ubuntu:~/Desktop$ gdb -c core.28569 程序名
GNU gdb (GDB) 7.2
版权所有 (C) 2010 Free Software Foundation, Inc.
许可 GPLv3+:GNU GPL 版本 3 或更高版本
这是免费软件:您可以自由更改和重新分发它。
在法律允许的范围内,不提供任何保证。输入“显示复制”
和“显示保修”了解详情。
此 GDB 配置为“--host=x86_64-linux-gnu --target=i386-linux-gnu”。
有关错误报告说明,请参阅:
...
从程序名中读取符号...完成。
[新线程28569]
核心是由“程序名”生成的。
程序以信号 6 终止,Aborted。
#0 0x00914410 在 __kernel_vsyscall ()
设置调试 gdb 的环境。
未定义函数“internal_error”。
在未来的共享库加载时使断点挂起?(y or [n]) [回答 N; 输入不是来自终端]
未定义函数“info_command”。
在未来的共享库加载时使断点挂起?(y or [n]) [回答 N; 输入不是来自终端]
.gdbinit:8:源命令文件中的错误:
需要参数(一个或多个断点编号)。
(gdb) BT
#0 0x00914410 在 __kernel_vsyscall ()
符号读取过程中,CFI数据不完整;未指定的寄存器(例如,eax)位于 0x914411。
#1 0x0804d7f4 in __unified_syscall()
#2 0xbf8966c0 在?? ()
#3  
#4 0x2054454e 在?? ()
#5 0x20524c43 在?? ()
#6 0x2e352e33 在?? ()
#7 0x32373033 在?? ()
#8 0x2e203b39 在?? ()
#9 0x2054454e 在?? ()
#10 0x20524c43 在?? ()
#11 0x2e302e33 在?? ()
#12 0x32373033 在?? ()
#13 0x4d203b39 在?? ()
#14 0x61696465 在?? ()
#15 0x6e654320 在?? ()
#16 0x20726574 在?? ()
#17 0x36204350 在?? ()
#18 0x203b302e 在?? ()
#19 0x54454e2e 在 ?? ()
#20 0x43302e34 在?? ()
#21 0x00000029 在?? ()
#22 0xbf8989a8 在?? ()
回溯停止:此帧内部的前一帧(损坏的堆栈?)
(gdb) bt 已满
#0 0x00914410 在 __kernel_vsyscall ()
没有可用的符号表信息。
#1 0x0804d7f4 in __unified_syscall()
没有可用的符号表信息。
#2 0xbf8966c0 在?? ()
没有可用的符号表信息。
#3  
没有可用的符号表信息。
#4 0x2054454e 在?? ()
没有可用的符号表信息。
#5 0x20524c43 在?? ()
没有可用的符号表信息。
#6 0x2e352e33 在?? ()
没有可用的符号表信息。
#7 0x32373033 在?? ()
没有可用的符号表信息。
#8 0x2e203b39 在?? ()
没有可用的符号表信息。
#9 0x2054454e 在?? ()
没有可用的符号表信息。
#10 0x20524c43 在?? ()
没有可用的符号表信息。
#11 0x2e302e33 在?? ()
没有可用的符号表信息。
#12 0x32373033 在?? ()
没有可用的符号表信息。
#13 0x4d203b39 在?? ()
没有可用的符号表信息。
#14 0x61696465 在?? ()
没有可用的符号表信息。
#15 0x6e654320 在?? ()
没有可用的符号表信息。
#16 0x20726574 在?? ()
没有可用的符号表信息。
#17 0x36204350 在?? ()
没有可用的符号表信息。
#18 0x203b302e 在?? ()
没有可用的符号表信息。
#19 0x54454e2e 在 ?? ()
没有可用的符号表信息。
#20 0x43302e34 在?? ()
没有可用的符号表信息。
#21 0x00000029 在?? ()
没有可用的符号表信息。
#22 0xbf8989a8 在?? ()
没有可用的符号表信息。
回溯停止:此帧内部的前一帧(损坏的堆栈?)
(gdb) 退出
4

2 回答 2

16

这是堆栈溢出。

#4  0x2054454e in ?? ()

这看起来像文本,“十”或“NET”

#5  0x20524c43 in ?? ()

“RLC”或“CLR”

等等。

将地址视为文本 - 看看您是否可以识别此文本覆盖您的堆栈的位置。

于 2011-03-13T15:26:12.527 回答
6

您的堆栈跟踪实际上很容易理解:

  • 你在某个地方有 SIGSEGV,
  • 你的信号处理程序做了它所做的任何事情,然后调用abort()
  • 哪个发出raise(2)系统调用,通过调用__unified_syscall()

在 GDB 中没有堆栈跟踪的原因是

  • __unified_syscall在汇编中实现,并且
  • 不使用帧指针,并且
  • 没有适当的cfi指令来描述如何从中放松。

我认为这是dietlibc 中的一个错误,实际上很容易修复。看看这个(未经测试的)补丁是否为您修复了它:

--- dietlibc-0.31/i386/unified.S.orig   2011-03-13 10:16:23.000000000 -0700
+++ dietlibc-0.31/i386/unified.S    2011-03-13 10:21:32.000000000 -0700
@@ -31,8 +31,14 @@ __unified_syscall:
    movzbl  %al, %eax
 .L1:
    push    %edi
+        cfi_adjust_cfa_offset (4)
+        cfi_rel_offset (edi, 0)
    push    %esi
+        cfi_adjust_cfa_offset (4)
+        cfi_rel_offset (esi, 0)
    push    %ebx
+        cfi_adjust_cfa_offset (4)
+        cfi_rel_offset (ebx, 0)
    movl    %esp,%edi
    /* we use movl instead of pop because otherwise a signal would
       destroy the stack frame and crash the program, although it
@@ -61,8 +67,11 @@ __unified_syscall:
 #endif
 .Lnoerror:
    pop %ebx
+        cfi_adjust_cfa_offset (-4)
    pop %esi
+        cfi_adjust_cfa_offset (-4)
    pop %edi
+        cfi_adjust_cfa_offset (-4)

 /* here we go and "reuse" the return for weak-void functions */
 #include "dietuglyweaks.h"

如果您无法重建dietlibc,或者补丁不正确,您仍然可以更好地分析堆栈跟踪。据我所知,__unified_syscall不碰%ebp。因此,您可以通过执行以下操作获得合理的堆栈跟踪:

define xbt
  set $xbp = (void **)$arg0
  while 1
    x/2a $xbp
    set $xbp = (void **)$xbp[0]
  end
end

xbt $ebp

注意:如果xbt工作,它很可能进入SIGSEGV信号帧周围的杂草(该帧也不使用帧指针)。这可能会导致完全垃圾,或跳过一两个帧(这正是SIGSEGV发生的帧)。

因此,将适当的展开描述符放入dietlibc 确实会好得多。

于 2011-03-13T17:31:44.883 回答